<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
    
  <meta name="description" content="林湃滨的个人博客" />
  
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
     滨书
  </title>
  <meta name="generator" content="hexo-theme-yilia-plus">
  
  <link rel="shortcut icon" href="/favicon.ico" />
  
  
<link rel="stylesheet" href="/css/style.css">

  
<script src="/js/pace.min.js"></script>


  

  

<link rel="alternate" href="/atom.xml" title="滨书" type="application/atom+xml">
</head>

</html>

<body>
  <div id="app">
    <main class="content">
      
<section class="cover">
    
  <div class="cover-frame">

    <div class="bg-box">
      <img src="/images/coverWLOP.jpg" alt="image frame" />
    </div>
      <iframe style="display: inline-block;float: right;margin: 10px;" frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=450 src="//music.163.com/outchain/player?type=0&id=4901576078&auto=1&height=430"></iframe>

    
    <div class="cover-inner text-center text-white">
      <h1><a href="/">滨书</a></h1>
      <div id="subtitle-box">
        
        <span id="subtitle"></span>
        
      </div>
      <div>
        
      </div>
    </div>
  </div>
  <div class="cover-learn-more">
    <a href="javascript:void(0)" class="anchor"><i class="ri-arrow-down-line"></i></a>
  </div>
</section>



<script src="https://cdn.jsdelivr.net/npm/typed.js@2.0.11/lib/typed.min.js"></script>


<div id="main">
  <section class="outer">
  <article class="articles">
    
    
    
    
    <article id="post-Redis/【Redis】内存数据满了会宕机吗" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2020/01/16/Redis/%E3%80%90Redis%E3%80%91%E5%86%85%E5%AD%98%E6%95%B0%E6%8D%AE%E6%BB%A1%E4%BA%86%E4%BC%9A%E5%AE%95%E6%9C%BA%E5%90%97/"
    >【Redis】Redis的内存淘汰策略</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/01/16/Redis/%E3%80%90Redis%E3%80%91%E5%86%85%E5%AD%98%E6%95%B0%E6%8D%AE%E6%BB%A1%E4%BA%86%E4%BC%9A%E5%AE%95%E6%9C%BA%E5%90%97/" class="article-date">
  <time datetime="2020-01-16T13:48:10.000Z" itemprop="datePublished">2020-01-16</time>
</a>
      
      
      
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h2 id="带着问题学习"><a href="#带着问题学习" class="headerlink" title="带着问题学习"></a>带着问题学习</h2><p><strong>Redis数据库内存满了的话，会不会造成宕机？</strong></p>
<h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><p>这问题一开始便有一坑，Redis并不会让内存数据存满这种情况发生。在使用Redis的时候，我们需要配置Redis能够使用的最大内存大小， 存到一定容量的时候还有Redis的内存淘汰策略呢，还有最近最少使用(LRU)算法进行淘汰，等等。。。 </p>
<h2 id="Redis占用内存"><a href="#Redis占用内存" class="headerlink" title="Redis占用内存"></a>Redis占用内存</h2><p>众所周知，Redis是基于内存的key-value数据库，因为系统的内存大小有限，在使用Redis的时候，可以配置Redis能使用的最大内存大小。</p>
<h3 id="配置方式"><a href="#配置方式" class="headerlink" title="配置方式"></a>配置方式</h3><ol>
<li><p>通过配置文件配置</p>
<p>通过在Redis安装目录下的redis.conf配置文件中添加以下配置，设置内存大小</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;&#x2F;设置Redis最大占用内存大小为100M&#96;</span><br><span class="line"></span><br><span class="line">maxmemory 100mb&#96;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>redis的配置文件不一定使用的是安装目录下的redis.conf文件，启动redis服务的时候可以通过传参指定redis使用的配置文件</p>
</blockquote>
</li>
<li><p>通过命令修改</p>
<p>Redis支持运行时通过命令动态修改内存大小</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">//设置Redis最大占用内存大小为100M`</span><br><span class="line">127.0.0.1:6379&gt; config set maxmemory 100mb`</span><br><span class="line"></span><br><span class="line">//获取设置的Redis能使用的最大内存大小`</span><br><span class="line">127.0.0.1:6379&gt; config get maxmemory`</span><br></pre></td></tr></table></figure>

<blockquote>
<p>如果不设置最大内存大小或者设置最大内存大小为0，在64位操作系统下不限制内存大小，在32位操作系统下最多使用3GB内存</p>
</blockquote>
</li>
</ol>
<h2 id="Redis的内存淘汰"><a href="#Redis的内存淘汰" class="headerlink" title="Redis的内存淘汰"></a>Redis的内存淘汰</h2><p>既然可以设置Redis最大占用内存大小，那么配置的内存就有用完的时候。那在内存用完的时候，还继续往Redis里面添加数据不就没内存可用了吗？</p>
<p>实际上Redis定义了几种策略用来处理这种情况：</p>
<p><strong>noeviction(默认策略)</strong>：对于写请求不再提供服务，直接返回错误（DEL请求和部分特殊请求除外）</p>
<p><strong>allkeys-lru</strong>：从所有key中使用LRU算法进行淘汰</p>
<p><strong>volatile-lru</strong>：从设置了过期时间的key中使用LRU算法进行淘汰</p>
<p><strong>allkeys-random</strong>：从所有key中随机淘汰数据</p>
<p><strong>volatile-random</strong>：从设置了过期时间的key中随机淘汰</p>
<p><strong>volatile-ttl</strong>：在设置了过期时间的key中，根据key的过期时间进行淘汰，越早过期的越优先被淘汰</p>
<blockquote>
<p> 当使用<strong>volatile-lru</strong>、<strong>volatile-random</strong>、<strong>volatile-ttl</strong>这三种策略时，如果没有key可以被淘汰，则和<strong>noeviction</strong>一样返回错误 </p>
</blockquote>
<h3 id="获取和设置内存淘汰策略"><a href="#获取和设置内存淘汰策略" class="headerlink" title="获取和设置内存淘汰策略"></a>获取和设置内存淘汰策略</h3><ul>
<li><p>获取当前内存淘汰策略</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; config get maxmemory-policy</span><br></pre></td></tr></table></figure>



</li>
</ul>
<ul>
<li><p>通过修改redis.conf文件设置淘汰策略</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">maxmemory-policy allkeys-lru</span><br></pre></td></tr></table></figure>



</li>
</ul>
<ul>
<li><p>通过命令修改淘汰策略</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; config set maxmemory-policy allkeys-lru`</span><br></pre></td></tr></table></figure>



</li>
</ul>
<h3 id="LRU算法"><a href="#LRU算法" class="headerlink" title="LRU算法"></a><strong>LRU算法</strong></h3><h5 id="什么是LRU"><a href="#什么是LRU" class="headerlink" title="什么是LRU?"></a>什么是LRU?</h5><p>上面说到了Redis可使用最大内存使用完了，是可以使用LRU算法进行内存淘汰的，那么什么是LRU算法呢？</p>
<blockquote>
<p><strong>LRU(Least Recently Used)</strong>，即最近最少使用，是一种缓存置换算法。在使用内存作为缓存的时候，缓存的大小一般是固定的。当缓存被占满，这个时候继续往缓存里面添加数据，就需要淘汰一部分老的数据，释放内存空间用来存储新的数据。这个时候就可以使用LRU算法了。其核心思想是：如果一个数据在最近一段时间没有被用到，那么将来被使用到的可能性也很小，所以就可以被淘汰掉。</p>
</blockquote>
<h3 id="LRU在Redis中的实现"><a href="#LRU在Redis中的实现" class="headerlink" title="LRU在Redis中的实现"></a><strong>LRU在Redis中的实现</strong></h3><h5 id="近似LRU算法"><a href="#近似LRU算法" class="headerlink" title="近似LRU算法"></a>近似LRU算法</h5><p>Redis使用的是近似LRU算法，它跟常规的LRU算法还不太一样。近似LRU算法通过随机采样法淘汰数据，每次随机出5（默认）个key，从里面淘汰掉最近最少使用的key。</p>
<blockquote>
<p>可以通过maxmemory-samples参数修改采样数量：例：maxmemory-samples 10 maxmenory-samples配置的越大，淘汰的结果越接近于严格的LRU算法</p>
</blockquote>
<p>Redis为了实现近似LRU算法，给每个key增加了一个额外增加了一个24bit的字段，用来存储该key最后一次被访问的时间。</p>
<h5 id="Redis3-0对近似LRU的优化"><a href="#Redis3-0对近似LRU的优化" class="headerlink" title="Redis3.0对近似LRU的优化"></a>Redis3.0对近似LRU的优化</h5><p>Redis3.0对近似LRU算法进行了一些优化。新算法会维护一个候选池（大小为16），池中的数据根据访问时间进行排序，第一次随机选取的key都会放入池中，随后每次随机选取的key只有在访问时间小于池中最小的时间才会放入池中，直到候选池被放满。当放满后，如果有新的key需要放入，则将池中最后访问时间最大（最近被访问）的移除。</p>
<p>当需要淘汰的时候，则直接从池中选取最近访问时间最小（最久没被访问）的key淘汰掉就行。</p>
<h3 id="LFU算法"><a href="#LFU算法" class="headerlink" title="LFU算法"></a><strong>LFU算法</strong></h3><p>LFU算法是Redis4.0里面新加的一种淘汰策略。它的全称是<strong>Least Frequently Used</strong>，它的核心思想是根据key的最近被访问的频率进行淘汰，很少被访问的优先被淘汰，被访问的多的则被留下来。</p>
<p>LFU算法能更好的表示一个key被访问的热度。假如你使用的是LRU算法，一个key很久没有被访问到，只刚刚是偶尔被访问了一次，那么它就被认为是热点数据，不会被淘汰，而有些key将来是很有可能被访问到的则被淘汰了。如果使用LFU算法则不会出现这种情况，因为使用一次并不会使一个key成为热点数据。</p>
<p>LFU一共有两种策略：</p>
<p>volatile-lfu：在设置了过期时间的key中使用LFU算法淘汰key</p>
<p>allkeys-lfu：在所有的key中使用LFU算法淘汰数据</p>
<blockquote>
<p>设置使用这两种淘汰策略跟前面讲的一样，不过要注意的一点是这两周策略只能在Redis4.0及以上设置，如果在Redis4.0以下设置会报错</p>
</blockquote>

      
      <!-- reward -->
      
    </div>
      <!-- copyright -->
      
    <footer class="article-footer">
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Redis/" rel="tag">Redis</a></li></ul>


    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-HashMap底层为什么时数组链表结构" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2020/01/16/HashMap%E5%BA%95%E5%B1%82%E4%B8%BA%E4%BB%80%E4%B9%88%E6%97%B6%E6%95%B0%E7%BB%84%E9%93%BE%E8%A1%A8%E7%BB%93%E6%9E%84/"
    >HashMap底层为什么时数组链表结构</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/01/16/HashMap%E5%BA%95%E5%B1%82%E4%B8%BA%E4%BB%80%E4%B9%88%E6%97%B6%E6%95%B0%E7%BB%84%E9%93%BE%E8%A1%A8%E7%BB%93%E6%9E%84/" class="article-date">
  <time datetime="2020-01-16T03:32:34.000Z" itemprop="datePublished">2020-01-16</time>
</a>
      
      
      
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h2 id="问题背景"><a href="#问题背景" class="headerlink" title="问题背景"></a>问题背景</h2><p>之前面试时问了HashMap的底层结构，详细见本人个人对HashMap和Hashtable底层实现的见解，入口如下：<br><a href="https://blog.csdn.net/weixin_40849588/article/details/88384922" target="_blank" rel="noopener">Java中HashMap与HashTable底层的联系与区别</a></p>
<p>之后被问到HashMap底层为什么是数组链表呢？这样的话，链表一长，在链表中查询的效率不是很低吗？<br>我：（哑了）<br>最近看到一个比较有依据的答案，在此做一下答复。</p>
<h2 id="HashMap底层为什么是数组链表呢？在链表中查询的效率不是很低吗？"><a href="#HashMap底层为什么是数组链表呢？在链表中查询的效率不是很低吗？" class="headerlink" title="HashMap底层为什么是数组链表呢？在链表中查询的效率不是很低吗？"></a>HashMap底层为什么是数组链表呢？在链表中查询的效率不是很低吗？</h2><p>在JDK1.7以及1.7版本之前，HashMap对数组元素即链表的查询确实是从头节点开始查询的，这样链表一旦长了，效率比较低也是意料之中。<br>而在1.8中对HashMap的数据结构进行了一定的优化，其中<strong>增加了一个阈值对数组元素进行判断是否有必要进行红黑树变形</strong>（红黑树是一种二叉查找树），一旦链表长度达到了阈值，其数据结构便会变形为红黑树，提高了查询效率，但插入的效率并没有链表头插法那么高，这也可能是HashMap底层为什么不用红黑树组成的数组的原因之一。<br>性能对比：</p>
<blockquote>
<ul>
<li>链表：插入复杂度O(1)，查找复杂度O(n)</li>
<li>红黑树：插入复杂度O(logn)，查找复杂度O(logn)</li>
</ul>
</blockquote>
<ul>
<li>HashMap数组元素为链表的时候，插入直接使用头插，插入复杂度O(1)；当链表较短时候，查找数据时对性能并没有什么影响，如果链表一长，查找起来就很影响性能了。 </li>
<li>在Java8中，如果链表长度到达了8个，就会转化为红黑树，提高了查找的性能，但每次插入新的数据，都得维护红黑树的结构，复杂度为O(logn)。这样算是对查找和插入元素时性能的一个权衡，毕竟存起来就是用来查的</li>
</ul>
<p>此是本人个人愚见，各位dalao如果有其他更有力度的答案，欢迎在评论区答复 （^_^）</p>

      
      <!-- reward -->
      
    </div>
      <!-- copyright -->
      
    <footer class="article-footer">
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Java/" rel="tag">Java</a></li></ul>


    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-部署云服务器" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2020/01/16/%E9%83%A8%E7%BD%B2%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8/"
    >部署云服务器</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/01/16/%E9%83%A8%E7%BD%B2%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8/" class="article-date">
  <time datetime="2020-01-16T03:18:21.000Z" itemprop="datePublished">2020-01-16</time>
</a>
      
      
      
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <p>[toc]</p>
<hr>
## 本文部署环境

<ul>
<li>阿里云</li>
<li>服务器系统：CentOS7</li>
</ul>
<h2 id="1、购买一个云服务器"><a href="#1、购买一个云服务器" class="headerlink" title="1、购买一个云服务器"></a>1、购买一个云服务器</h2><blockquote>
<p>我自己使用的是阿里云，其他服务器的操作也都是类似的</p>
</blockquote>
<ul>
<li><a href="http://aliyun.com/" target="_blank" rel="noopener">阿里云官网地址</a></li>
<li><a href="https://cloud.tencent.com/" target="_blank" rel="noopener">腾讯云官网地址</a></li>
<li><a href="https://activity.huaweicloud.com/promotion/index.html" target="_blank" rel="noopener">华为云官网地址</a></li>
</ul>
<h3 id="试用套餐"><a href="#试用套餐" class="headerlink" title="试用套餐"></a>试用套餐</h3><p>如果你是学生或者新注册用户，一般可以使用学生优惠或着有新用户的免费试用，用来学习部署云服务器最为合适。</p>
<p><a href="https://free.aliyun.com/ntms/free/personal.html?handle=true" target="_blank" rel="noopener">阿里云免费试用套餐</a></p>
<h3 id="购买服务器"><a href="#购买服务器" class="headerlink" title="购买服务器"></a>购买服务器</h3><ol>
<li><p>服务器的地域都可以，我本人选的华南。</p>
</li>
<li><p>镜像版本<br> 不论是CentOS还是Ubuntu，只要是Linux的版本都行，就是不建议Window Sever<br> <img src="https://img-blog.csdnimg.cn/20190709150102315.png" alt="选择镜像版本"></p>
<hr>

</li>
</ol>
<h2 id="2、去控制台查看服务器状态"><a href="#2、去控制台查看服务器状态" class="headerlink" title="2、去控制台查看服务器状态"></a>2、去控制台查看服务器状态</h2><p><img src="https://img-blog.csdnimg.cn/20190709143703940.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="首页进入控制台"><br><img src="https://img-blog.csdnimg.cn/20190709143821756.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="查看云服务器ECS"></p>
<p><img src="https://img-blog.csdnimg.cn/20190709160537605.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="查看服务器"><br>如果没有实例的话，需要自己去手动创建（购买）：<br><img src="https://img-blog.csdnimg.cn/20190709151051921.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<hr>

<h2 id="3、设置安全组"><a href="#3、设置安全组" class="headerlink" title="3、设置安全组"></a>3、设置安全组</h2><p>所谓的安全组，是指服务器开放什么端口，默认只开放22和3389端口。<br>其中，入方向指外网访问服务器的端口，出方向指服务器对外网进行访问的端口。<br><img src="https://img-blog.csdnimg.cn/201907091603536.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>配置安全组<br><img src="https://img-blog.csdnimg.cn/20190709154057327.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="点击配置规则"><br>在入方向点击添加安全组规则，<br><img src="https://img-blog.csdnimg.cn/20190709154238376.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190709154850515.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>安全组配置完成后，需要对具体的实例导入刚刚配置好的安全组规则：</p>
<p><img src="https://img-blog.csdnimg.cn/20190709160239768.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>重置密码<br><img src="https://img-blog.csdnimg.cn/201907091602016.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<hr>

<h2 id="4、下载操作工具"><a href="#4、下载操作工具" class="headerlink" title="4、下载操作工具"></a>4、下载操作工具</h2><p>工具：<br>MobaXterm：<a href="https://mobaxterm.mobatek.net/download.html" target="_blank" rel="noopener">官网下载</a><br>Navicat：<a href="https://pan.baidu.com/s/1CmsVRsbuGRbdvF4zHm5qoQ" target="_blank" rel="noopener">百度云（附激活码）</a></p>
<h3 id="1、连接登录："><a href="#1、连接登录：" class="headerlink" title="1、连接登录："></a>1、连接登录：</h3><p><img src="https://img-blog.csdnimg.cn/20190709161601305.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h3 id="2、连接成功效果"><a href="#2、连接成功效果" class="headerlink" title="2、连接成功效果"></a>2、连接成功效果</h3><p><img src="https://img-blog.csdnimg.cn/20190709155925338.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>之后服务器就部署好了，之后只需要给服务器配置好对应的开发环境配置（如Java开发环境、Tomcat等），便可以耍起来啦~，之后会拿出些时间努力写一篇将Web服务部署到云服务器上的、比较详尽的文章。</p>

      
      <!-- reward -->
      
    </div>
      <!-- copyright -->
      
    <footer class="article-footer">
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8/" rel="tag">云服务器</a></li></ul>


    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-【面经】计算机网络" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2020/01/16/%E3%80%90%E9%9D%A2%E7%BB%8F%E3%80%91%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"
    >【面经】计算机网络</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/01/16/%E3%80%90%E9%9D%A2%E7%BB%8F%E3%80%91%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/" class="article-date">
  <time datetime="2020-01-16T03:13:06.000Z" itemprop="datePublished">2020-01-16</time>
</a>
      
      
      
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <p>[toc]</p>
<hr>

<h2 id="一、三次握手和四次挥手"><a href="#一、三次握手和四次挥手" class="headerlink" title="一、三次握手和四次挥手"></a>一、三次握手和四次挥手</h2><h3 id="（一）、三次握手（建立连接）"><a href="#（一）、三次握手（建立连接）" class="headerlink" title="（一）、三次握手（建立连接）"></a>（一）、三次握手（建立连接）</h3><ol>
<li><p>第一次握手：（Client：我要和你建立连接）</p>
<p>客户端Client将标志位SYN置为1，Seq=J（随机产生），并将数据包发送给服务器端Server，客户端进入SYN_SENT状态，等待Server确认</p>
</li>
<li><p>第二次握手：（Server：你真的要和我建立连接吗？）</p>
<p>Server端收到数据包，由SYN=1可知Client请求建立连接，Server将标志位SYN和确认位置为1，ack=J+1，并置seq=K（随机产生），并将该数据包发送给Client以确认连接请求，Server端进入SYN_RCVD状态。</p>
</li>
<li><p>第三次握手：（Client：我真的要和你建立连接。OK！）</p>
<p>Client端收到确认后，检查ack是否为J+1，确认位是否为1；如果是则将标志位ACK置为1，ack=K+1，之后将该数据包发送给Server端。Server端检查ack是否为K+1，确认位ACK是否为1，正确则连接建立成功，Client和Server两端都进入ESTABLISHED状态，完成三次握手，随后Client和Server之间可以开始传输数据了。</p>
</li>
</ol>
<h3 id="（二）、四次挥手（断开连接）"><a href="#（二）、四次挥手（断开连接）" class="headerlink" title="（二）、四次挥手（断开连接）"></a>（二）、四次挥手（断开连接）</h3><ol>
<li><p>第一次挥手：（Client：我要和你断开连接）</p>
<p>Client端发送一个FIN（finish，FIN占用一个序号），<strong>用于关闭Client到Server端的数据传送</strong>，Client进入FIN_WAIT_1状态。</p>
</li>
<li><p>第二次挥手：（Server：好吧，断吧）</p>
<p>Server端收到FIN后，发送一个ACK给Client端，确认序号ack为FIN序号+1，Server端进入CLOSE_WAIT状态，此时TCP连接处于半关闭状态（客户端已经没有数据发送给服务端，但服务端如果有数据要发送，客户端还是要接收的）。</p>
</li>
<li><p>第三次挥手：（Server：我也要和你断开连接）</p>
<p>Server端发送一个FIN，<strong>用于关闭Server和Client的数据传送</strong>，Server进入LAST_ACK状态。</p>
</li>
<li><p>第四次挥手：（Client：好吧，断吧）</p>
<p>Client收到FIN后，Client进入TIME_WAIT状态，接着发送一个ACK给Server端，ack为FIN序号+1，Server进入CLOSED状态，至此四次挥手结束，完成断开连接。</p>
</li>
</ol>
<hr>

<h2 id="二、为什么TCP连接需要三次握手，两次不可以吗？"><a href="#二、为什么TCP连接需要三次握手，两次不可以吗？" class="headerlink" title="二、为什么TCP连接需要三次握手，两次不可以吗？"></a>二、为什么TCP连接需要三次握手，两次不可以吗？</h2><pre><code>**防止已失效的链接请求报文突然又送到了服务端Server**，因而产生错误，使服务器一直等待建立链接，浪费服务器端的资源。</code></pre><p>　客户端发出的连接请求报文并未丢失，而是在某个网络节点长时间滞留了，以致延误到链接释放以后的某个时间才到达Server。这是，Server误以为这是Client发出的一个新的链接请求，于是就向客户端发送确认数据包，同意建立链接。</p>
<p>若不采用“三次握手”，那么只要Server发出确认数据包，新的链接就建立了。由于client此时并未发出建立链接的请求，所以其不会理睬Server的确认，也不与Server通信；而这时Server一直在等待Client的请求，这样Server就白白浪费了一定的资源。若采用“三次握手”，在这种情况下，由于Server端没有收到来自客户端的确认，则就会知道Client并没有要求建立请求，就不会建立链接。</p>
<hr>

<h2 id="三、保证TCP连接的可靠性"><a href="#三、保证TCP连接的可靠性" class="headerlink" title="三、保证TCP连接的可靠性"></a>三、保证TCP连接的可靠性</h2><pre><code>TCP协议提供一种面向连接的、可靠的字节流服务。面向连接意味着：客户端Client与服务器端Server之间在传输数据之前必须先建立一个TCP连接。字节流服务是指两个应用程序之间通过TCP连接交换８ｂｉｔ字节构成的字节流，而TCP不在字节流中插入记录标识符。</code></pre><p>TCP通过以下方式保证传输的可靠性：</p>
<p>１.　数据包校验</p>
<pre><code>目的是检测数据在传输过程中的任何变化，若校验出包有错，则对其报文段并且不给出响应，这时TCP发送数据段超时后会重发数据。</code></pre><p>２.　对失序数据包重排序</p>
<pre><code>IP数据包的到达可能是失序的，而TCP报文段是作为IP数据报来传输的，因此TCP报文段的到达也可能是失序的。因此TCP会对失序数据进行重新排序，然后再交给应用层。</code></pre><p>３.　丢弃重复数据</p>
<pre><code>对于重复数据，能够丢弃重复数据。</code></pre><p>４.　应答机制</p>
<pre><code>当TCP收到发自TCP连接另一端的数据，它将发送一个确认。（这个确认并不是立即发送的，通常会推迟几分之一秒）</code></pre><p>５.　超时重传</p>
<pre><code>当TCP发出一个段后，它启动一个定时器，等待目的端确认收到这个报文段。如果不能及时收到一个确认，将重发这个报文段。</code></pre><p>６.　流量控制</p>
<pre><code>TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据，这可以防止较快主机致使较慢主机的缓冲区溢出，这便是流量控制。TCP使用的流量控制协议为大小可变的滑动窗口协议。</code></pre><hr>

<h2 id="四、DDos攻击"><a href="#四、DDos攻击" class="headerlink" title="四、ＤＤｏｓ攻击"></a>四、ＤＤｏｓ攻击</h2><h3 id="含义"><a href="#含义" class="headerlink" title="含义"></a>含义</h3><ol>
<li>Client端向Server端发送请求连接数据包</li>
<li>Server端向Client端发送确认数据包</li>
<li>Client端并没有向Server端发送确认数据包，服务器一直等待来自客户端的确认</li>
</ol>
<h3 id="DDos的预防"><a href="#DDos的预防" class="headerlink" title="DDos的预防"></a>DDos的预防</h3><blockquote>
<p>DDos无法彻底地根治，除非不使用TCP协议</p>
</blockquote>
<ul>
<li>限制同时打开SYN半连接数目</li>
<li>缩短SYN半连接的TIME OUT超时时间</li>
<li>关闭不必要的服务</li>
</ul>
<hr>

<h2 id="五、TCP和UDP的区别"><a href="#五、TCP和UDP的区别" class="headerlink" title="五、TCP和UDP的区别"></a>五、TCP和UDP的区别</h2><p>TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议都属于传输层协议，它们之间的区别包括：</p>
<ul>
<li>TCP是面向连接的，UDP是无连接的；</li>
<li>TCP是可靠的，UDP是不可靠的；</li>
<li>TCP只支持点对点通信，UDP支持一对一、一对多、多对一、多对多的通信模式；</li>
<li>TCP是面向字节流的，UDP是面向报文的；</li>
<li>TCP有拥塞控制机制，UDP没有拥塞控制机制，适合媒体的通信</li>
<li>TCP首部开销（20个字节）比UDP的首部开销（８个字节）要大。</li>
</ul>
<hr>

<h2 id="六、TCP的拥塞控制"><a href="#六、TCP的拥塞控制" class="headerlink" title="六、TCP的拥塞控制"></a>六、TCP的拥塞控制</h2><pre><code>在某段时间，对网络中某一个资源的需求超过了该资源所能提供的可用部分，网络的性能就会变坏，这种情况就叫做拥塞。</code></pre><blockquote>
<p>网络资源：计算机网络中的带宽、交换节点中的缓存以及处理机等。</p>
</blockquote>
<pre><code>拥塞控制便是防止过多的数据注入到网络中，避免网络中的路由器或链路过载。

拥塞控制与流量控制不同。拥塞控制是网络链路全局性的控制过程，而流量控制是指点对点通信量的控制。</code></pre><h3 id="拥塞控制的四种方法"><a href="#拥塞控制的四种方法" class="headerlink" title="拥塞控制的四种方法"></a>拥塞控制的四种方法</h3><ol>
<li><p>慢启动（慢开始）：</p>
<pre><code>一开始不发送大量的数据，从１开始以２倍规律增大探测网络的拥塞程度，即从小到大逐渐增加拥塞窗口的大小。</code></pre></li>
<li><p>拥塞避免：</p>
<pre><code>拥塞避免算法是让拥塞窗口缓慢增大，每经过一个RTT往返时间就将发送方的拥塞窗口加1（慢开始门限ssthresh也会随着增加），使拥塞窗口按线性规律缓慢增加。</code></pre></li>
<li><p>快重传：</p>
<pre><code>接收方在收到一个失序的报文段后立即发出对上个接收到的报文的重复确认，使发送方及早发现有报文段没有到达对方。

   在快重传算法中，发送方只要连续收到三个重复确认就应该立即发送对方尚未收到的报文段，而不必接续等待设置的重传计时器时间到期。</code></pre><p><img src="https://img-blog.csdnimg.cn/2019072300000268.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h5><center>快重传</center></h5></li>
<li><p>快恢复：</p>
<pre><code>快恢复算法与快重传配合使用。当发送方收到三个重复确认时，将慢开始门限ssthresh门限减半（称“乘法减小”），cwnd也设为与ssthresh一般大小，然后执行拥塞避免算法。</code></pre></li>
</ol>
<hr>

<h2 id="OSI七层模型"><a href="#OSI七层模型" class="headerlink" title="OSI七层模型"></a>OSI七层模型</h2><p>OSI模型从低到高有：</p>
<ul>
<li>物理层：<pre><code>物理层规定了激活、维持、关闭通信端点之间的机械特性、电气特性、功能特性、过程特性。该层为上层协议提供了一个传输数据的物理媒体。
在物理层，数据的单位为**比特（bit）**，属于物理层定义的典型规范代表包括：EIA／TIA　RS－２３２，EIA／TIA　RS－４４９，RJ－４５等等。</code></pre></li>
<li>数据链路层<pre><code>数据链路层在不可靠的物理介质上提供可靠的传输。该层的作用包括：物理地址寻址，数据封装成帧，流量控制，数据检错、重发等。
数据链路层协议的代表：SDLC、ＨＤＬＣ、PPP、STP、帧中继等。在这一层的数据称为帧（frame）</code></pre></li>
<li>网络层<pre><code>网络层负责对子网间的数据包进行路由选择。网络层还有拥塞控制，网际互连等功能。
网络层协议的代表有：IP、IPX、RIP、OSPF等；在这一层的数据称为数据包（package）。</code></pre></li>
<li>传输层<pre><code>传输层是第一个端到端（即主机到主机）的层次。传输层负责将上层数据分段并提供端到端的、可靠或不可靠的传输。此外传输层还要处理端到端的差错控制和流量控制问题。
传输层协议的代表：TCP、UDP、SPX等。在这一层的数据的单位称为数据段（segment）。</code></pre></li>
<li>会话层<pre><code>会话层管理主机之间的会话进程，即负责建立、管理、终止进程之间的会话。此外，会话层利用在数据中插入校检点来实现数据的同步。</code></pre></li>
<li>表示层<pre><code>表示层对上层数据或信息进行变换以保证一个主机应用层信息可以被另一个主机的应用程序理解。表示层的数据转换包括数据的加密、压缩、格式转换等。</code></pre></li>
<li>应用层<pre><code>应用层为操作系统或网络应用程序提供访问网络服务的接口等。应用层协议的代表包括：Telnet(23/tcp)、FTP（21/tcp）、SMTP（２５/tcp）、HTTP（80/tcp）、DNS（５３/tcp或udp）、SNMP(161/udp)等。</code></pre></li>
</ul>
<blockquote>
<p>待更新……</p>
</blockquote>

      
      <!-- reward -->
      
    </div>
      <!-- copyright -->
      
    <footer class="article-footer">
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E9%9D%A2%E7%BB%8F/" rel="tag">面经</a></li></ul>


    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-Java/Java内存模型" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2020/01/16/Java/Java%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B/"
    >Java内存模型</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/01/16/Java/Java%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B/" class="article-date">
  <time datetime="2020-01-16T03:11:51.000Z" itemprop="datePublished">2020-01-16</time>
</a>
      
      
      
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <p>[toc]</p>
<h1 id="Java内存模型（JMM）"><a href="#Java内存模型（JMM）" class="headerlink" title="Java内存模型（JMM）"></a>Java内存模型（JMM）</h1><pre><code>JMM全称Java Memory Model 。其实JMM并不像JVM内存结构一样是真实存在的。他只是一个抽象的概念。

JMM是和多线程相关的，他描述了一组规则或规范，这个规范定义了一个线程对共享变量的写入时对另一个线程是可见的。</code></pre><h2 id="一-、JMM定义"><a href="#一-、JMM定义" class="headerlink" title="(一)、JMM定义"></a>(一)、JMM定义</h2><pre><code>Java内存模型（Java Memory Model ,JMM），一种符合内存模型规范的，屏蔽了各种硬件和操作系统的访问差异的，保证了Java程序在各种平台下对内存的访问都能得到一致效果的机制及规范。其目的是解决由于多线程通过共享内存进行通信时，存在的**原子性**、**可见性**（缓存一致性）以及**有序性**问题。</code></pre><br>

<h3 id="原子性问题"><a href="#原子性问题" class="headerlink" title="原子性问题"></a>原子性问题</h3><pre><code>线程是CPU调度的基本单位。

CPU有时间片的概念，会根据不同的调度算法进行线程调度。所以在多线程场景下，就会发生原子性问题。因为线程在执行一个读改写操作时，在执行完读改之后，时间片耗完，就会被要求放弃CPU，并等待重新调度。这种情况下，读改写就不是一个原子操作。即存在原子性问题。</code></pre><br>

<h3 id="可见性问题（缓存一致性）"><a href="#可见性问题（缓存一致性）" class="headerlink" title="可见性问题（缓存一致性）"></a>可见性问题（缓存一致性）</h3><pre><code>在多核CPU，多线程的场景中，每个核都至少有一个L1 缓存。多个线程访问进程中的某个共享内存，且这多个线程分别在不同的核心上执行，则每个核心都会在各自的caehe中保留一份共享内存的缓冲。由于多核是可以并行的，可能会出现**多个线程同时写各自的缓存**的情况，而各自的cache之间的数据就有可能不同。

在CPU和主存之间增加缓存，在多线程场景下就可能存在缓存一致性问题，也就是说，在多核CPU中，每个核的自己的缓存中，关于同一个数据的缓存内容可能不一致。</code></pre><br>
### 有序性问题

<pre><code>除了引入了时间片以外，由于处理器优化和指令重排等，CPU还可能对输入代码进行乱序执行，比如load-&gt;add-&gt;save 有可能被优化成load-&gt;save-&gt;add 。这就是有序性问题。
为了保证共享内存的正确性（可见性、有序性、原子性），内存模型定义了共享内存系统中多线程程序读写操作行为的规范。通过这些规则来规范对内存的读写操作，从而保证指令执行的正确性。它与处理器有关、与缓存有关、与并发有关、与编译器也有关。他解决了CPU多级缓存、处理器优化、指令重排等导致的内存访问问题，保证了并发场景下的一致性、原子性和有序性。

针对上面的这些问题，不同的操作系统都有不同的解决方案，而Java语言为了屏蔽掉底层的差异，定义了一套属于Java语言的内存模型规范，即Java内存模型。</code></pre><p><img src="https://img-blog.csdnimg.cn/20190712024138117.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="Java内存模型"><h5><center>Java内存模型</center></h5><br><br></p>
<hr>

<h2 id="（二）、JMM实现"><a href="#（二）、JMM实现" class="headerlink" title="（二）、JMM实现"></a>（二）、JMM实现</h2><pre><code>在Java中提供了一系列和并发处理相关的关键字，比如 _volatile_ 、_synchronized_、_final_、_concurren_ 包等。其实这些就是Java内存模型封装了底层的实现后提供给程序员使用的一些关键字。

在开发多线程的代码的时候，我们可以直接使用synchronized等关键字来控制并发，从来就不需要关心底层的编译器优化、缓存一致性等问题。所以，Java内存模型，除了定义了一套规范，还提供了一系列原语，封装了底层实现后，供开发者直接使用。

那么，在Java中，是分别使用什么方式来保证原子性、可见性和有序性呢？</code></pre><h3 id="原子性"><a href="#原子性" class="headerlink" title="原子性"></a>原子性</h3><pre><code>在Java中，为了保证原子性，提供了两个高级的字节码指令monitorenter和monitorexit，这两个字节码，在Java中对应的关键字就是synchronized。

因此，在Java中可以使用synchronized来保证方法和代码块内的操作是原子性的。</code></pre><h3 id="可见性"><a href="#可见性" class="headerlink" title="可见性"></a>可见性</h3><pre><code>Java内存模型是通过在变量修改后将新值同步回主内存，在变量读取前从主内存刷新变量值的这种依赖主内存作为传递媒介的方式来实现的。

Java中的volatile关键字提供了一个功能，那就是被其修饰的变量在被修改后可以立即同步到主内存，被其修饰的变量在每次是用之前都从主内存刷新。因此，可以使用volatile来保证多线程操作时变量的可见性。</code></pre><blockquote>
<p> 除了volatile，Java中的synchronized和final两个关键字也可以实现可见性，只不过实现方式不同。</p>
</blockquote>
<h3 id="有序性"><a href="#有序性" class="headerlink" title="有序性"></a>有序性</h3><pre><code>在Java中，可以使用synchronized和volatile来保证多线程之间操作的有序性。实现方式有所区别：</code></pre><ul>
<li><p>volatile关键字会禁止指令重排。</p>
</li>
<li><p>synchronized关键字保证同一时刻只允许一条线程操作。</p>
<p>  在简单介绍完Java并发编程中解决原子性、可见性以及有序性可以使用的关键字后，这个synchronized关键字似乎在每个地方都有它，它可以同时满足以上三种特性，这其实也是很多人滥用synchronized的原因。</p>
<p>但是<strong>synchronized是比较影响性能的</strong>，虽然编译器提供了很多锁优化技术，也不建议过度使用。</p>
</li>
</ul>

      
      <!-- reward -->
      
    </div>
      <!-- copyright -->
      
    <footer class="article-footer">
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Java/" rel="tag">Java</a></li></ul>


    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-Redis安装配置及数据类型" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2020/01/16/Redis%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE%E5%8F%8A%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/"
    >Redis安装配置及数据类型</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/01/16/Redis%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE%E5%8F%8A%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/" class="article-date">
  <time datetime="2020-01-16T03:08:34.000Z" itemprop="datePublished">2020-01-16</time>
</a>
      
      
      
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <p>[toc]</p>
<p>Redis，一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可以持久化的日志型、Key-Value数据库，并提供多种语言的API；</p>
<blockquote>
<p>Redis像是一个HashMap，但它不在JVM中运行，而是以一个独立进程的形式运行。</p>
</blockquote>
<pre><code>数据的存取速度比数据库（Mysql）快，一般会被当作缓存使用，所以常用的数据可以考虑放在这里以**提高性能**。</code></pre><h2 id="Redis安装"><a href="#Redis安装" class="headerlink" title="Redis安装"></a>Redis安装</h2><h3 id="Window安装"><a href="#Window安装" class="headerlink" title="Window安装"></a>Window安装</h3><p><a href="https://github.com/dmajkic/redis/downloads" target="_blank" rel="noopener">window安装地址</a></p>
<p>下载到的Redis支持32bit和64bit。根据自己实际情况选择，将64bit的内容cp到自定义盘符安装目录取名redis。 如 G:\redis。<br>1、打开运行根目录下的 <strong>redis-server.exe</strong> ，运行窗口保持打开状态，不要关了。</p>
<blockquote>
<p>想方便的话，可以将redis的路径加入到系统的环境变量之中，就省得输路径了</p>
<p><img src="https://img-blog.csdnimg.cn/20190803005923736.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>2、再打开目录下的<strong>redis-cli.exe</strong>，或者执行命令： redis-cli.exe -h 127.0.0.1 -p 6379<br><img src="https://img-blog.csdnimg.cn/20190803010150494.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
</blockquote>
<h2 id="Redis配置"><a href="#Redis配置" class="headerlink" title="Redis配置"></a>Redis配置</h2><p>Redis的配置文件位于Redis安装目录中，文件名为redis.conf</p>
<p>通过CONFIG命令查看和设置配置项</p>
<h3 id="1、查看配置"><a href="#1、查看配置" class="headerlink" title="1、查看配置"></a>1、查看配置</h3><p>命令格式：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis 127.0.0.1:6379&gt; CONFIG GET CONFIG_SETTING_NAME</span><br></pre></td></tr></table></figure>

<p>例：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">redis 127.0.0.1:6379&gt; CONFIG GET loglevel</span><br><span class="line"></span><br><span class="line">1) &quot;loglevel&quot;</span><br><span class="line">2) &quot;notice&quot;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>使用符号 * 获取所有配置项</p>
</blockquote>
<h3 id="2、修改配置"><a href="#2、修改配置" class="headerlink" title="2、修改配置"></a>2、修改配置</h3><p>命令格式：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis 127.0.0.1:6379&gt; CONFIG SET CONFIG_SETTING_NAME NEW_CONFIG_VALUE</span><br></pre></td></tr></table></figure>



<p>例：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">redis 127.0.0.1:6379&gt; CONFIG SET loglevel &quot;notice&quot;</span><br><span class="line">OK</span><br><span class="line">redis 127.0.0.1:6379&gt; CONFIG GET loglevel</span><br><span class="line"></span><br><span class="line">1) &quot;loglevel&quot;</span><br><span class="line">2) &quot;notice&quot;</span><br></pre></td></tr></table></figure>



<h3 id="3、配置项参数说明"><a href="#3、配置项参数说明" class="headerlink" title="3、配置项参数说明"></a>3、配置项参数说明</h3><ol>
<li><p>daemonize：Redis默认不是以守护进程的方式运行，可以通过该配置项修改为yes启用守护进程。</p>
<blockquote>
<p>当redis以守护进程方式运行时，redis默认会把pid写入/var/run/redis.pid文件，可通过pidfile指定：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pidfile &#x2F;var&#x2F;run&#x2F;redis.pid</span><br></pre></td></tr></table></figure>


</blockquote>
</li>
<li><p>port：指定reids监听端口，默认端口为6379 。</p>
</li>
<li><p>bind：绑定的主机地址，默认127.0.0.1</p>
</li>
<li><p>timeout：客户端闲置多长时间关闭连接，若为0，表示关闭该功能</p>
</li>
<li><p>loglevel：日志记录级别。</p>
<blockquote>
<p>redis总共支持四个级别：debug、verbose、notice、warning，默认为verbose</p>
</blockquote>
</li>
<li><p>databases：设置数据库的数量，默认为0，可使用SELECT &lt;dbid&gt; 命令在连接上指定数据库id</p>
</li>
<li><p>save &lt;seconds&gt;  &lt;changes&gt; ：表示在多长时间内 (以s为单位) 有几次更新操作，将数据同步到数据文件。</p>
<blockquote>
<p>redis中默认配置文件中提供了三个条件：</p>
<ul>
<li>save 900 1</li>
<li>save 300 10</li>
<li>save 60 10000</li>
</ul>
</blockquote>
</li>
<li><p>rdbcompression：指定存储到本地数据库时是否压缩数据，默认为yes。</p>
<blockquote>
<p>redis采用LZF压缩，如果为了节省CPU时间，可以关闭该选项，但会导致数据库文件大小变得很大</p>
</blockquote>
</li>
<li><p>dbfilename：指定本地数据库文件名，默认值为dump.rdb</p>
</li>
<li><p>dir：指定本地数据库存放目录</p>
</li>
<li><p>slaveof &lt;masterip&gt; &lt;masterport&gt;：</p>
<blockquote>
<p>设置当本机为slav服务时，设置master服务的ip地址以及端口，在redis启动时候，会自动从master进行数据同步</p>
</blockquote>
</li>
<li><p>masterauth &lt;master-password&gt;：当master服务设置了密码保护时候，slav服务连接master的密码。</p>
</li>
<li><p>requirepass foobared：</p>
<p>设置redis连接密码，如果设置了连接密码，客户端在连接redis时候需要通过AUTH &lt;password&gt; 命令提供密码，默认no</p>
</li>
<li><p>maxclients 128：</p>
<pre><code>&gt; 设置同一时间最大客户端连接数，默认无限制。
&gt;
&gt; Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数，_如果设置 maxclients 0，表示不作限制_。
&gt;
&gt; 当客户端连接数到达限制时，Redis会关闭新的连接并向客户端返回max number of clients reached错误信息</code></pre></li>
<li><p>maxmemory &lt;bytes&gt;：指定Redis最大内存限制</p>
<blockquote>
<p>Redis在启动时会把数据加载到内存中，达到最大内存后，Redis会先尝试清除已到期或即将到期的Key，当此方法处理后，仍然到达最大内存设置，将无法再进行写入操作，但仍然可以进行读取操作。</p>
<p>Redis新的vm机制，会把Key存放内存，Value会存放在swap区</p>
</blockquote>
</li>
<li><p>appendonly no ：指定是否在每次更新操作后进行日志记录，默认为no</p>
<blockquote>
<p>Redis在默认情况下是异步的把数据写入磁盘，如果不开启，可能会在断电时导致一段时间内的数据丢失。</p>
<p>因为 redis本身同步数据文件是按上面save条件来同步的，所以有的数据会在一段时间内只存在于内存中。</p>
</blockquote>
</li>
<li><p>appendfilename appendonly.aof：指定更新日志文件名，默认为appendonly.aof</p>
</li>
<li><p>appendfsync everysec：指定更新日志条件。</p>
<blockquote>
<p>共有三个可选值：</p>
<ul>
<li>no：表示等操作系统进行数据缓存同步到磁盘（快）</li>
<li>always：表示每次更新操作后手动调用fsync()将数据写到磁盘（慢，安全）</li>
<li>everysec：表示每秒同步一次（折中，默认）</li>
</ul>
</blockquote>
</li>
<li><p>vm-enabled no：指定是否启用虚拟内存机制，默认值为no</p>
<blockquote>
<p>VM机制将数据进行分页存放，由Redis将访问量较少的页即冷数据swap到磁盘上，访问多的页面由磁盘自动换出到内存中</p>
</blockquote>
</li>
<li><p>vm-swap-file /tmp/redis.swap：虚拟内存文件路径，默认为/tmp/redis.swap，多个redis实例不可共享。</p>
</li>
<li><p>vm-max-memory 0 ：将所有大于vm-max-memory的数据存入虚拟内存中，默认为0。</p>
<blockquote>
<p>Redis的所有索引数据（即keys）都是存储在内存当中的，无论vm-max-memory设置为何值。</p>
<p>当vm-max-memory设置为0 时，其实便是所有value都存在于磁盘。</p>
</blockquote>
</li>
<li><p>vm-page-size 32：指定swap文件中page的大小，默认为32bytes。</p>
<blockquote>
<p>Redis的swap文件分成了很多的page，一个对象可以保存在多个page上面，但一个page上不能被多个对象共享。</p>
<p>vm-page-size是要根据存储的 数据大小来设定的,如果存储很多小对象，page大小最好设置为32或者64bytes；如果存储很大大对象，则可以使用更大的page，如果不 确定，就使用默认值</p>
</blockquote>
</li>
<li><p>vm-pages 134217728：指定swap文件中的page数量，默认大小为 2<sup>27</sup>即134217728。</p>
</li>
<li><p>vm-max-threads 4：设置访问swap文件的线程数，默认值为4。</p>
<blockquote>
<p>最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的，可能会造成比较长时间的延迟。</p>
</blockquote>
</li>
<li><p>glueoutputbuf yes：设置在想客户端应答时，是否把较小的包合并为一个包发送，默认为开启。</p>
</li>
<li><p>hash-max-zipmap-entries 64：指定在超过一定的数量时，采用一种特殊的哈希算法</p>
</li>
<li><p>hash-max-zipmap-value 512：指定在最大的元素超过某一临界值时，采用一种特殊的哈希算法</p>
</li>
<li><p>activerehashing yes：指定是否激活重置哈希，默认为yes</p>
</li>
<li><p>include /path/to/local.conf ：指定包含其他的配置文件，可以在同一主机上多个redis实例之间使用同一份配置文件，同时各个实例也拥有自己特定的配置文件。</p>
</li>
</ol>
<h2 id="Redis的数据类型"><a href="#Redis的数据类型" class="headerlink" title="Redis的数据类型"></a>Redis的数据类型</h2><p>Redis中有5种数据类型：</p>
<ul>
<li>String    字符串</li>
<li>List        列表</li>
<li>Hash        字典</li>
<li>Set        集合</li>
<li>Sorted Set    有序集合</li>
</ul>
<p>不同的数据类型，有不同的命令方式。</p>
<h3 id="String-相关命令"><a href="#String-相关命令" class="headerlink" title="String 相关命令"></a>String 相关命令</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">set (key) (value)			设置key = value</span><br><span class="line">append (key) (value2)		在key对应的value尾部追加value2</span><br><span class="line">get	(key)					获取key对应的value</span><br><span class="line">incr (key)				将key对应的value加1</span><br><span class="line">incrby (key) (value1)		将key对应的value加上value1</span><br><span class="line">ttl (key)					获取key到期的剩余时间</span><br><span class="line">rename (key) (key_new)		对key重命名</span><br><span class="line"></span><br><span class="line">SET key value                   设置key=value</span><br><span class="line">GET key                         或者键key对应的值</span><br><span class="line">GETRANGE key start end          得到字符串的子字符串存放在一个键</span><br><span class="line">GETSET key value                设置键的字符串值，并返回旧值</span><br><span class="line">GETBIT key offset               返回存储在键位值的字符串值的偏移</span><br><span class="line">MGET key1 [key2..]              得到所有的给定键的值</span><br><span class="line">SETBIT key offset value         设置或清除该位在存储在键的字符串值偏移</span><br><span class="line">SETEX key seconds value         键到期时设置值</span><br><span class="line">SETNX key value                 设置键的值，只有当该键不存在</span><br><span class="line">SETRANGE key offset value       覆盖字符串的一部分从指定键的偏移</span><br><span class="line">STRLEN key                      得到存储在键的值的长度</span><br><span class="line">MSET key value [key value...]   设置多个键和多个值</span><br><span class="line">MSETNX key value [key value...] 设置多个键多个值，只有在当没有按键的存在时</span><br><span class="line">PSETEX key milliseconds value   设置键的毫秒值和到期时间</span><br><span class="line">INCR key                        增加键的整数值一次</span><br><span class="line">INCRBY key increment            由给定的数量递增键的整数值</span><br><span class="line">INCRBYFLOAT key increment       由给定的数量递增键的浮点值</span><br><span class="line">DECR key                        递减键一次的整数值</span><br><span class="line">DECRBY key decrement            由给定数目递减键的整数值</span><br><span class="line">APPEND key value                追加值到一个键</span><br><span class="line">DEL key                         如果存在删除键</span><br><span class="line">DUMP key                        返回存储在指定键的值的序列化版本</span><br><span class="line">EXISTS key                      此命令检查该键是否存在</span><br><span class="line">EXPIRE key seconds              指定键的过期时间</span><br><span class="line">EXPIREAT key timestamp          指定的键过期时间。在这里，时间是在Unix时间戳格式</span><br><span class="line">PEXPIRE key milliseconds        设置键以毫秒为单位到期</span><br><span class="line">PEXPIREAT key milliseconds-timestamp        设置键在Unix时间戳指定为毫秒到期</span><br><span class="line">KEYS pattern                    查找与指定模式匹配的所有键</span><br><span class="line">MOVE key db                     移动键到另一个数据库</span><br><span class="line">PERSIST key                     移除过期的键</span><br><span class="line">PTTL key                        以毫秒为单位获取剩余时间的到期键。</span><br><span class="line">TTL key                         获取键到期的剩余时间。</span><br><span class="line">RANDOMKEY                       从Redis返回随机键</span><br><span class="line">RENAME key newkey               更改键的名称</span><br><span class="line">RENAMENX key newkey             重命名键，如果新的键不存在</span><br><span class="line">TYPE key                        返回存储在键的数据类型的值。</span><br></pre></td></tr></table></figure>

<h3 id="List-列表"><a href="#List-列表" class="headerlink" title="List 列表"></a>List 列表</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">lpush (listkey) (value)			给listkey列表添加(一个或多个)元素（在前面添加）</span><br><span class="line">rpush (listkey) (value)			给listkey列表添加(一个或多个)元素(在后面添加)</span><br><span class="line">llen (listkey)					获取listkey的长度</span><br><span class="line">lrange (listkey) (start) (end)	从start位置至end位置获取其中的元素</span><br><span class="line"></span><br><span class="line">BLPOP key1 [key2 ] timeout 取出并获取列表中的第一个元素，或阻塞，直到有可用</span><br><span class="line">BRPOP key1 [key2 ] timeout 取出并获取列表中的最后一个元素，或阻塞，直到有可用</span><br><span class="line">BRPOPLPUSH source destination timeout 从列表中弹出一个值，它推到另一个列表并返回它;或阻塞，直到有可用</span><br><span class="line">LINDEX key index 从一个列表其索引获取对应的元素</span><br><span class="line">LINSERT key BEFORE|AFTER pivot value 在列表中的其他元素之后或之前插入一个元素</span><br><span class="line">LLEN key 获取列表的长度</span><br><span class="line">LPOP key 获取并取出列表中的第一个元素</span><br><span class="line">LPUSH key value1 [value2] 在前面加上一个或多个值的列表</span><br><span class="line">LPUSHX key value 在前面加上一个值列表，仅当列表中存在</span><br><span class="line">LRANGE key start stop 从一个列表获取各种元素</span><br><span class="line">LREM key count value 从列表中删除元素</span><br><span class="line">LSET key index value 在列表中的索引设置一个元素的值</span><br><span class="line">LTRIM key start stop 修剪列表到指定的范围内</span><br><span class="line">RPOP key 取出并获取列表中的最后一个元素</span><br><span class="line">RPOPLPUSH source destination 删除最后一个元素的列表，将其附加到另一个列表并返回它</span><br><span class="line">RPUSH key value1 [value2] 添加一个或多个值到列表</span><br><span class="line">RPUSHX key value 添加一个值列表，仅当列表中存在</span><br></pre></td></tr></table></figure>



<h3 id="Hash字典，哈希表"><a href="#Hash字典，哈希表" class="headerlink" title="Hash字典，哈希表"></a>Hash字典，哈希表</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">hset person (key) (value)		设置person哈希表中的key键对应值为value</span><br><span class="line">hgetall person					显示person哈希表中所有的key和value</span><br><span class="line">hkeys person					显示person哈希表中所有的keys</span><br><span class="line">hvals person					</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">HDEL key field[field...] 删除对象的一个或几个属性域，不存在的属性将被忽略</span><br><span class="line">HEXISTS key field 查看对象是否存在该属性域</span><br><span class="line">HGET key field 获取对象中该field属性域的值</span><br><span class="line">HGETALL key 获取对象的所有属性域和值</span><br><span class="line">HINCRBY key field value 将该对象中指定域的值增加给定的value，原子自增操作，只能是integer的属性值可以使用</span><br><span class="line">HINCRBYFLOAT key field increment 将该对象中指定域的值增加给定的浮点数</span><br><span class="line">HKEYS key 获取对象的所有属性字段</span><br><span class="line">HVALS key 获取对象的所有属性值</span><br><span class="line">HLEN key 获取对象的所有属性字段的总数</span><br><span class="line">HMGET key field[field...] 获取对象的一个或多个指定字段的值</span><br><span class="line">HSET key field value 设置对象指定字段的值</span><br><span class="line">HMSET key field value [field value ...] 同时设置对象中一个或多个字段的值</span><br><span class="line">HSETNX key field value 只在对象不存在指定的字段时才设置字段的值</span><br><span class="line">HSTRLEN key field 返回对象指定field的value的字符串长度，如果该对象或者field不存在，返回0.</span><br><span class="line">HSCAN key cursor [MATCH pattern] [COUNT count] 类似SCAN命令</span><br></pre></td></tr></table></figure>



<h3 id="Set集合"><a href="#Set集合" class="headerlink" title="Set集合"></a>Set集合</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">SADD key member [member ...] 	添加一个或者多个元素到集合(set)里</span><br><span class="line">SCARD key 						获取集合里面的元素数量</span><br><span class="line">SDIFF key [key ...] 			获得队列不存在的元素</span><br><span class="line">SDIFFSTORE destination key [key ...] 获得队列不存在的元素，并存储在一个关键的结果集</span><br><span class="line">SINTER key [key ...] 			获得两个集合的交集</span><br><span class="line">SINTERSTORE destination key [key ...] 获得两个集合的交集，并存储在一个集合中</span><br><span class="line">SISMEMBER key member 			确定一个给定的值是一个集合的成员</span><br><span class="line">SMEMBERS key 					获取集合里面的所有key</span><br><span class="line">SMOVE source destination member 移动集合里面的一个key到另一个集合</span><br><span class="line">SPOP key [count] 				获取并删除一个集合里面的元素</span><br><span class="line">SRANDMEMBER key [count] 		从集合里面随机获取一个元素</span><br><span class="line">SREM key member [member ...] 	从集合里删除一个或多个元素，不存在的元素会被忽略</span><br><span class="line">SUNION key [key ...] 			添加多个set元素</span><br><span class="line">SUNIONSTORE destination key [key ...] 合并set元素，并将结果存入新的set里面</span><br><span class="line">SSCAN key cursor [MATCH pattern] [COUNT count] 迭代set里面的元素</span><br></pre></td></tr></table></figure>

<h3 id="Sorted-Set有序集合"><a href="#Sorted-Set有序集合" class="headerlink" title="Sorted Set有序集合"></a>Sorted Set有序集合</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"> </span><br><span class="line">ZADD key score1 member1 [score2 member2] </span><br><span class="line">							添加一个或多个成员到有序集合，或者如果它已经存在更新其分数</span><br><span class="line">ZCARD key 					得到的有序集合成员的数量</span><br><span class="line">ZCOUNT key min max 			计算一个有序集合成员与给定值范围内的分数</span><br><span class="line">ZINCRBY key increment member 在有序集合增加成员的分数</span><br><span class="line">ZINTERSTORE destination numkeys key [key ...] </span><br><span class="line">							多重交叉排序集合，并存储生成一个新的键有序集合。</span><br><span class="line">ZLEXCOUNT key min max 		计算一个给定的字典范围之间的有序集合成员的数量</span><br><span class="line">ZRANGE key start stop [WITHSCORES] 由索引返回一个成员范围的有序集合（从低到高）</span><br><span class="line">ZRANGEBYLEX key min max [LIMIT offset count]返回一个成员范围的有序集合（由字典范围）</span><br><span class="line">ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] </span><br><span class="line">							返回有序集key中，所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员，有序集成员按 score 值递增(从小到大)次序排列</span><br><span class="line">ZRANK key member 			确定成员的索引中有序集合</span><br><span class="line">ZREM key member [member ...] 从有序集合中删除一个或多个成员，不存在的成员将被忽略</span><br><span class="line">ZREMRANGEBYLEX key min max 	删除所有成员在给定的字典范围之间的有序集合</span><br><span class="line">ZREMRANGEBYRANK key start stop 在给定的索引之内删除所有成员的有序集合</span><br><span class="line">ZREMRANGEBYSCORE key min max 在给定的分数之内删除所有成员的有序集合</span><br><span class="line">ZREVRANGE key start stop [WITHSCORES] </span><br><span class="line">							返回一个成员范围的有序集合，通过索引，以分数排序，从高分到低分</span><br><span class="line">ZREVRANGEBYSCORE key max min [WITHSCORES] </span><br><span class="line">							返回一个成员范围的有序集合，以socre排序从高到低</span><br><span class="line">ZREVRANK key member 		确定一个有序集合成员的索引，以分数排序，从高分到低分</span><br><span class="line">ZSCORE key member 			获取给定成员相关联的分数在一个有序集合</span><br><span class="line">ZUNIONSTORE destination numkeys key [key ...] </span><br><span class="line">							添加多个集排序，所得排序集合存储在一个新的键</span><br><span class="line">ZSCAN key cursor [MATCH pattern] [COUNT count] 增量迭代排序元素集和相关的分数</span><br></pre></td></tr></table></figure>
      
      <!-- reward -->
      
    </div>
      <!-- copyright -->
      
    <footer class="article-footer">
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Redis/" rel="tag">Redis</a></li></ul>


    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-http各个版本的区别" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2020/01/16/http%E5%90%84%E4%B8%AA%E7%89%88%E6%9C%AC%E7%9A%84%E5%8C%BA%E5%88%AB/"
    >http各个版本的区别</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/01/16/http%E5%90%84%E4%B8%AA%E7%89%88%E6%9C%AC%E7%9A%84%E5%8C%BA%E5%88%AB/" class="article-date">
  <time datetime="2020-01-16T03:06:50.000Z" itemprop="datePublished">2020-01-16</time>
</a>
      
      
      
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <p>[toc]</p>
<h1 id="http1-0、1-1和2-0的区别"><a href="#http1-0、1-1和2-0的区别" class="headerlink" title="http1.0、1.1和2.0的区别"></a>http1.0、1.1和2.0的区别</h1><h2 id="一、1-0与1-1"><a href="#一、1-0与1-1" class="headerlink" title="一、1.0与1.1"></a>一、1.0与1.1</h2><h3 id="1、缓存处理"><a href="#1、缓存处理" class="headerlink" title="1、缓存处理"></a>1、缓存处理</h3><ul>
<li>在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准，</li>
<li>HTTP1.1则引入了更多的缓存控制策略例如Entity tag，If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。</li>
</ul>
<h3 id="2、带宽优化和网络连接的使用"><a href="#2、带宽优化和网络连接的使用" class="headerlink" title="2、带宽优化和网络连接的使用"></a>2、带宽优化和网络连接的使用</h3><ul>
<li>HTTP1.0中，存在一些<strong>浪费带宽</strong>的现象，例如客户端只是需要某个对象的一部分，而服务器却将整个对象送过来了，并且不支持断点续传功能，</li>
<li>HTTP1.1则在请求头引入了range头域，它允许只请求资源的某个部分，即返回码是206（Partial Content），这样就方便了开发者自由的选择以便于充分利用带宽和连接</li>
</ul>
<h3 id="3、错误通知的管理"><a href="#3、错误通知的管理" class="headerlink" title="3、错误通知的管理"></a>3、错误通知的管理</h3><ul>
<li>在HTTP1.1中<strong>新增了24个错误状态响应码</strong>，如409（Conflict）表示请求的资源与资源的当前状态发生冲突；410（Gone）表示服务器上的某个资源被永久性的删除。</li>
</ul>
<h3 id="4、Host头处理"><a href="#4、Host头处理" class="headerlink" title="4、Host头处理"></a>4、Host头处理</h3><ul>
<li>在HTTP1.0中认为<strong>每台服务器都绑定一个唯一的IP地址</strong>，因此，请求消息中的URL并没有传递主机名（hostname）。但随着虚拟主机技术的发展，在一台物理服务器上可以存在多个虚拟主机（Multi-homed Web Servers），并且它们共享一个IP地址。</li>
<li>HTTP1.1的请求消息和响应消息都应支持Host头域，且请求消息中如果没有Host头域会报告一个错误（400 Bad Request）。</li>
</ul>
<h3 id="5、长连接"><a href="#5、长连接" class="headerlink" title="5、长连接"></a>5、长连接</h3><ul>
<li>HTTP 1.1支持<strong>长连接（PersistentConnection）</strong>和<strong>请求的流水线（Pipelining）处理</strong>，在一个TCP连接上可以传送多个HTTP请求和响应，减少了建立和关闭连接的消耗和延迟，在HTTP1.1中默认开启Connection： keep-alive，一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。</li>
</ul>
<h2 id="二、1-x-的优化"><a href="#二、1-x-的优化" class="headerlink" title="二、1.x 的优化"></a>二、1.x 的优化</h2><p>2012年google提出了SPDY的方案，优化了HTTP1.X的请求延迟，解决了HTTP1.X的安全性，具体如下：</p>
<ol>
<li><p><strong>降低延迟</strong>，针对HTTP高延迟的问题，SPDY优雅的采取了多路复用（multiplexing）。多路复用通过多个请求stream共享一个tcp连接的方式，解决了HOL blocking的问题，降低了延迟同时提高了带宽的利用率。</p>
</li>
<li><p><strong>请求优先级</strong>（request prioritization）。多路复用带来一个新的问题是，在连接共享的基础之上有可能会导致关键请求被阻塞。SPDY允许给每个request设置优先级，这样重要的请求就会优先得到响应。比如浏览器加载首页，首页的html内容应该优先展示，之后才是各种静态资源文件，脚本文件等加载，这样可以保证用户能第一时间看到网页内容。</p>
</li>
<li><p><strong>header压缩</strong>。前面提到HTTP1.x的header很多时候都是重复多余的。选择合适的压缩算法可以减小包的大小和数量。</p>
</li>
<li><p><strong>基于HTTPS的加密协议传输</strong>，大大提高了传输数据的可靠性。</p>
</li>
<li><p><strong>服务端推送</strong>（server push），采用了SPDY的网页，例如我的网页有一个sytle.css的请求，在客户端收到sytle.css数据的同时，服务端会将sytle.js的文件推送给客户端，当客户端再次尝试获取sytle.js时就可以直接从缓存中获取到，不用再发请求了。</p>
<blockquote>
<p>SPDY位于HTTP之下，TCP和SSL之上，如此可以在兼容老版本HTTP协议的同时使用已有的SSL功能</p>
</blockquote>
</li>
</ol>
<h2 id="三、HTTP２-０：SPDY升级版"><a href="#三、HTTP２-０：SPDY升级版" class="headerlink" title="三、HTTP２.０：SPDY升级版"></a>三、HTTP２.０：SPDY升级版</h2><p>HTTP2.0也是基于SPDY设计的，但其与SPDY仍有不同之处：</p>
<ul>
<li><p>2.0支持明文http传输，而SPDY强制使用HTTPS；</p>
</li>
<li><p>2.0消息头的压缩算法采用HPACK，而不是SPDY采用的DEFLATE：</p>
<blockquote>
<p>HPACK:<a href="http://http2.github.io/http2-spec/compression.html" target="_blank" rel="noopener">http://http2.github.io/http2-spec/compression.html</a></p>
<p>DEFLATE:<a href="http://zh.wikipedia.org/wiki/DEFLATE" target="_blank" rel="noopener">http://zh.wikipedia.org/wiki/DEFLATE</a></p>
</blockquote>
</li>
</ul>
<h3 id="与1-x相比，2-0的新特性"><a href="#与1-x相比，2-0的新特性" class="headerlink" title="与1.x相比，2.0的新特性"></a>与1.x相比，2.0的新特性</h3><h4 id="1、新的二进制格式"><a href="#1、新的二进制格式" class="headerlink" title="1、新的二进制格式"></a>1、新的二进制格式</h4><p>HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷，文本的表现形式有多样性，要做到健壮性考虑的场景必然很多。</p>
<p>HTTP2.0的协议解析采用二进制格式，与文本不同，二进制格式只认0和1的组合，实现方便且健壮。</p>
<h4 id="2、多路复用（MultiPlexing）"><a href="#2、多路复用（MultiPlexing）" class="headerlink" title="2、多路复用（MultiPlexing）"></a>2、多路复用（MultiPlexing）</h4><p>连接共享，即每一个request都是用作连接共享机制的。一个request对应一个id，这样一个连接上可以有多个request，每个连接的request可以随机的混杂在一起，接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。</p>
<h4 id="3、header压缩"><a href="#3、header压缩" class="headerlink" title="3、header压缩"></a>3、header压缩</h4><p>HTTP1.x的header中带有大量信息，而且每次都要重复发送，而HTTP2.0使用encoder来减少需要传输的header大小，通讯双方各自cache一份header fields表，既避免了重复header的传输，又减小了需要传输的大小。</p>
<h4 id="4、服务端推送（server-push）"><a href="#4、服务端推送（server-push）" class="headerlink" title="4、服务端推送（server push）"></a>4、服务端推送（server push）</h4><p>同SPDY一样，HTTP2.0也具有server push功能。</p>
<h1 id="附：HTTPS和HTTP的一些区别"><a href="#附：HTTPS和HTTP的一些区别" class="headerlink" title="附：HTTPS和HTTP的一些区别"></a>附：HTTPS和HTTP的一些区别</h1><ol>
<li>HTTPS协议需要CA证书（数字证书），一般是需要交费的</li>
<li>HTTP协议运行在TCP上，所有传输的内容都是明文传输，HTTPS运行在SSL/TLS之上，SSL/TLS运行在TCP之上，所有传输的内容都是经过加密的。</li>
<li>HTTP和HTTPS使用的是完全不同的连接方式，使用的端口不同，HTTP是80端口，HTTPS是４4３端口；</li>
<li>HTTPS能够有效地防止运营商劫持。</li>
</ol>

      
      <!-- reward -->
      
    </div>
      <!-- copyright -->
      
    <footer class="article-footer">
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/" rel="tag">基础知识</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/" rel="tag">计算机网络</a></li></ul>


    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-LeetCode/在编译器中刷LeetCode" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2020/01/16/LeetCode/%E5%9C%A8%E7%BC%96%E8%AF%91%E5%99%A8%E4%B8%AD%E5%88%B7LeetCode/"
    >在编译器中刷LeetCode</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/01/16/LeetCode/%E5%9C%A8%E7%BC%96%E8%AF%91%E5%99%A8%E4%B8%AD%E5%88%B7LeetCode/" class="article-date">
  <time datetime="2020-01-16T03:04:06.000Z" itemprop="datePublished">2020-01-16</time>
</a>
      
      
      
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <p>[toc]</p>
<h1 id="在Idea中刷LeetCode"><a href="#在Idea中刷LeetCode" class="headerlink" title="在Idea中刷LeetCode"></a>在Idea中刷LeetCode</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>  在IDE中解决LeetCode问题,支持<code>leetcode.com</code>与<code>leetcode-cn.com</code>,满足基本的做题需求。<br>  理论上支持: IntelliJ IDEA  PhpStorm  WebStorm  PyCharm  RubyMine  AppCode  CLion  GoLand  DataGrip  Rider MPS  Android Studio。  </p>
<h2 id="使用方式"><a href="#使用方式" class="headerlink" title="使用方式"></a>使用方式</h2><p align="center">
  <img src="https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/leetcode-editor-3.0.gif" alt="demo"/>
</p>  


<h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><ul>
<li><strong>通过插件库安装</strong> <a href="https://plugins.jetbrains.com/plugin/12132-leetcode-editor" target="_blank" rel="noopener">https://plugins.jetbrains.com/plugin/12132-leetcode-editor</a>  </li>
<li><strong>下载文件安装</strong> <a href="https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/leetcode-editor.zip" target="_blank" rel="noopener">https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/leetcode-editor.zip</a>  </li>
</ul>
<p><img src="https://img-blog.csdnimg.cn/20190723024842494.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190723025148329.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>安装后记得重启Idea。</p>
<h3 id="配置-第一次安装需要先配置"><a href="#配置-第一次安装需要先配置" class="headerlink" title="配置(第一次安装需要先配置)"></a>配置(第一次安装需要先配置)</h3><p> <img src="https://img-blog.csdnimg.cn/20190723024706996.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<ul>
<li><strong>配置路径</strong>: <code>File</code> -&gt; <code>settings</code>-&gt;<code>tools</code>-&gt;<code>leetcode plugin</code>  <ul>
<li><strong><code>URL可选项</code></strong>: <code>leetcode.com</code>与<code>leetcode-cn.com</code>  </li>
<li><strong><code>Code Type</code></strong>: <code>Java</code>,<code>Python</code>,<code>C++</code>,<code>Python3</code>,<code>C</code>,<code>C#</code>,<code>JavaScript</code>,<code>Ruby</code>,<code>Swift</code>,<code>Go</code> ,<code>Scala</code>,<code>Kotlin</code>,<code>Rust</code>,<code>PHP</code>   </li>
<li><strong><code>LoginName</code></strong>: 登录用户名</li>
<li><strong><code>Password</code></strong>: 登录密码  </li>
<li><strong><code>Temp File Path</code></strong>: 临时文件存放目录  </li>
</ul>
</li>
</ul>
<h3 id="打开Leetcode窗口（主窗口右下角的LeetCode图标）"><a href="#打开Leetcode窗口（主窗口右下角的LeetCode图标）" class="headerlink" title="打开Leetcode窗口（主窗口右下角的LeetCode图标）"></a>打开Leetcode窗口（主窗口右下角的LeetCode图标）</h3><p><img src="https://img-blog.csdnimg.cn/20190723025314253.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDg0OTU4OA==,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<ul>
<li><p><strong>工具栏</strong>:<br>如果账号信息没错的话（默认网络良好），工具栏会有Leetcode题库，就可以刷题了（妙啊~）<br><img src="https://img-blog.csdnimg.cn/20190723025416978.png" alt="在这里插入图片描述"></p>
<ul>
<li><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NodXppanVuL2xlZXRjb2RlLWVkaXRvci9tYXN0ZXIvZG9jL2xvZ2luLnBuZw" alt="login"><strong><code>登录</code></strong>:两个网站的登录帐号不互通，切换网站需配置对应的用户  </li>
<li><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NodXppanVuL2xlZXRjb2RlLWVkaXRvci9tYXN0ZXIvZG9jL2xvZ291dC5wbmc" alt="logout"><strong><code>退出</code></strong>:退出当前账户,如遇到登录错误,尝试先进行退出  </li>
<li><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NodXppanVuL2xlZXRjb2RlLWVkaXRvci9tYXN0ZXIvZG9jL3JlZnJlc2gucG5n" alt="refresh"><strong><code>刷新</code></strong>:在未登录的情况下也可查看刷新加载题目，但是无法提交  </li>
<li><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NodXppanVuL2xlZXRjb2RlLWVkaXRvci9tYXN0ZXIvZG9jL2ZpbmQucG5n" alt="find"><strong><code>查找</code></strong>:输入内容后回车搜索，再次回车搜索下一个，只会搜索题库节点下  </li>
<li><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NodXppanVuL2xlZXRjb2RlLWVkaXRvci9tYXN0ZXIvZG9jL2NvbGxhcHNlQWxsLnBuZw" alt="collapse"><strong><code>折叠</code></strong>:折叠全部节点.  </li>
<li><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NodXppanVuL2xlZXRjb2RlLWVkaXRvci9tYXN0ZXIvZG9jL2NvbmZpZy5wbmc" alt="config"><strong><code>配置</code></strong>:快捷跳转到配置界面  </li>
<li><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3NodXppanVuL2xlZXRjb2RlLWVkaXRvci9tYXN0ZXIvZG9jL2NsZWFyLnBuZw" alt="clear"><strong><code>清理</code></strong>:清理配置的缓存目录下的文件，两个网站对应的缓存目录不同，只会清理当前配置的网站下的。部分题目未提交的情况下慎重清理  </li>
</ul>
</li>
<li><p><strong>树</strong>:  </p>
<ul>
<li><strong><code>Problems</code></strong>:全部题目  </li>
<li><strong><code>Difficulty</code></strong>:难度分类  </li>
<li><strong><code>Tags</code></strong>:类型分类  </li>
<li><strong><code>Explore</code></strong>:探索内容,只包含题目,收费内容不支持;部分题目加载有顺序限制   </li>
<li><strong><code>颜色</code></strong>:题目颜色代表题目难度  </li>
<li><strong><code>符号</code></strong>:题目前<code>√</code>与<code>？</code>代表当前题目解答状态,探索下有 <code>$</code> 开头的为付费或者其他情况下无法查看的   </li>
</ul>
</li>
</ul>
<h3 id="菜单"><a href="#菜单" class="headerlink" title="菜单"></a>菜单</h3><p><img src="https://img-blog.csdnimg.cn/20190723025724286.png" alt="在这里插入图片描述"></p>
<ul>
<li><strong>菜单(在题目上右击出现)</strong>:  <ul>
<li><strong><code>open question</code></strong>:打开题目,在题目上双击也可以打开  </li>
<li><strong><code>Submit</code></strong>:提交题目  </li>
<li><strong><code>Submissions</code></strong>:查看提交记录,在弹出的窗口上选择记录查看详情(<code>Show detail</code>)  </li>
<li><strong><code>Run Code</code></strong>:运行代码,默认使用题目的测试用例  </li>
<li><strong><code>Testcase</code></strong>:自定义测试用例  </li>
<li><strong><code>Clear cache</code></strong>:清理当前题目</li>
</ul>
</li>
</ul>

      
      <!-- reward -->
      
    </div>
      <!-- copyright -->
      
    <footer class="article-footer">
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/LeetCode/" rel="tag">LeetCode</a></li></ul>


    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-Java/Java重写比较器" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2020/01/16/Java/Java%E9%87%8D%E5%86%99%E6%AF%94%E8%BE%83%E5%99%A8/"
    >Java重写比较器</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/01/16/Java/Java%E9%87%8D%E5%86%99%E6%AF%94%E8%BE%83%E5%99%A8/" class="article-date">
  <time datetime="2020-01-16T03:02:11.000Z" itemprop="datePublished">2020-01-16</time>
</a>
      
      
      
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h1 id="重写Comparetor"><a href="#重写Comparetor" class="headerlink" title="重写Comparetor"></a>重写Comparetor</h1><h3 id="1、Comparetor简单比较"><a href="#1、Comparetor简单比较" class="headerlink" title="1、Comparetor简单比较"></a>1、Comparetor简单比较</h3><p>Java中的排序默认是升序排序，重写为降序如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">       List&lt;Integer&gt; list = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">           Interval intemp = <span class="keyword">new</span> Interval(i,ia);</span><br><span class="line">           list.add(intemp);</span><br><span class="line">       &#125;</span><br><span class="line">       Collections.sort(list, <span class="keyword">new</span> Comparator&lt;Integer&gt;() &#123;</span><br><span class="line">           <span class="meta">@Override</span></span><br><span class="line">           <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Integer i1, Integer i2)</span> </span>&#123;</span><br><span class="line">               <span class="keyword">if</span> (i1 &gt; i2) &#123;</span><br><span class="line">                   <span class="keyword">return</span> -<span class="number">1</span>; <span class="comment">//不用交换</span></span><br><span class="line">               &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                   <span class="keyword">return</span> <span class="number">0</span>;	<span class="comment">//其他情况交换</span></span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;);</span><br><span class="line">       <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; list.size(); i++) &#123;</span><br><span class="line">           System.out.println(list.get(i));</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>



<h3 id="2、Comparetor对自定义对象排序"><a href="#2、Comparetor对自定义对象排序" class="headerlink" title="2、Comparetor对自定义对象排序"></a>2、Comparetor对自定义对象排序</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyComparetor</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">int</span> ia = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Interval</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> start;</span><br><span class="line">        <span class="keyword">int</span> end;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Interval</span><span class="params">(<span class="keyword">int</span> start,<span class="keyword">int</span> end)</span></span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.start = start;</span><br><span class="line">            <span class="keyword">this</span>.end = end;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        List&lt;Interval&gt; list = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">            Interval intemp = <span class="keyword">new</span> Interval(i,ia);</span><br><span class="line">            list.add(intemp);</span><br><span class="line">        &#125;</span><br><span class="line">        Collections.sort(list, <span class="keyword">new</span> Comparator&lt;Object&gt;() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Object o1, Object o2)</span> </span>&#123;</span><br><span class="line">                Interval i1 = (Interval)o1;</span><br><span class="line">                Interval i2 = (Interval)o2;</span><br><span class="line">                <span class="keyword">if</span> (i1.start-i1.end &gt; i2.start-i2.end) &#123;</span><br><span class="line">                    <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; list.size(); i++) &#123;</span><br><span class="line">            System.out.println(list.get(i).start - list.get(i).end);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
      
      <!-- reward -->
      
    </div>
      <!-- copyright -->
      
    <footer class="article-footer">
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Java/" rel="tag">Java</a></li></ul>


    </footer>

  </div>

  

  
  
  

  

</article>
    
    <article id="post-Mybatis中的resultMap解析" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2020/01/15/Mybatis%E4%B8%AD%E7%9A%84resultMap%E8%A7%A3%E6%9E%90/"
    >【Mybatis】resultMap解析</a
  >
</h2>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/2020/01/15/Mybatis%E4%B8%AD%E7%9A%84resultMap%E8%A7%A3%E6%9E%90/" class="article-date">
  <time datetime="2020-01-15T14:02:06.000Z" itemprop="datePublished">2020-01-15</time>
</a>
      
      
      
      
    </div>
    

    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h1 id="ResultMap解析"><a href="#ResultMap解析" class="headerlink" title="ResultMap解析"></a>ResultMap解析</h1><p>在Mybatis中，resultMap节点定义了结果集和结果对象（JavaBean）之间的映射规则。</p>
<p>本文章主要讲述的是resultMap的解析。</p>
<h2 id="相关基础类"><a href="#相关基础类" class="headerlink" title="相关基础类"></a>相关基础类</h2><h3 id="1、ResultMapping：列映射类"><a href="#1、ResultMapping：列映射类" class="headerlink" title="1、ResultMapping：列映射类"></a>1、ResultMapping：列映射类</h3><p>ResultMapping对象记录了结果集中的一列与对应JavaBean中一个属性的映射关系；</p>
<blockquote>
<p>文章参考：</p>
<p> <a href="https://www.cnblogs.com/homejim/p/9833863.html" target="_blank" rel="noopener">列映射类ResultMapping</a> </p>
</blockquote>
<h3 id="2、ResultMap：结果集映射类ResultMap"><a href="#2、ResultMap：结果集映射类ResultMap" class="headerlink" title="2、ResultMap：结果集映射类ResultMap"></a>2、ResultMap：结果集映射类ResultMap</h3><p>ResultMap对应的是结果集中的一个结果集。其基本组成部分中，含有ResultMapping对象。</p>
<blockquote>
<p>文章参考：</p>
<p><a href="https://www.cnblogs.com/homejim/p/9840373.html" target="_blank" rel="noopener">结果集映射类ResultMap</a></p>
</blockquote>
<h2 id="解析"><a href="#解析" class="headerlink" title="解析"></a>解析</h2><h3 id="入口函数"><a href="#入口函数" class="headerlink" title="入口函数"></a>入口函数</h3><p>resultMap是解析Mapper的一个环节，其处于mapper.xml文件下。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">resultMapElements(context.evalNodes(<span class="string">"/mapper/resultMap"</span>));</span><br></pre></td></tr></table></figure>

<p>解析是可以存在多个的，故 <code>context.evalNodes(&quot;/mapper/resultMap&quot;)</code>返回的是一个List列表。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">resultMapElements</span><span class="params">(List&lt;XNode&gt; list)</span><span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">    <span class="keyword">for</span>(XNode resultMapNode:list)&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            resultMapElement(resultMapNode);</span><br><span class="line">        &#125;<span class="keyword">catch</span>(IncompleteElementException e)&#123;</span><br><span class="line">            <span class="comment">//ignore,it will be retried</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="resultMapElement函数"><a href="#resultMapElement函数" class="headerlink" title="resultMapElement函数"></a>resultMapElement函数</h3><p>整个过程都是在resultMapElement这个函数中进行的，相关代码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> ResultMap <span class="title">resultMapElement</span><span class="params">(XNode resultMapNode)</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> resultMapElement(resultMapNode,Collections,&lt;ResultMapping&gt; emptyList());</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 处理&lt;resultMap&gt;节点，将节点解析成ResultMap对象，下面包含有ResultMapping对象组成的列表</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> resultMapNode resultMap节点</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> additionalResultMappings 另外的ResultMapping列</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> ResultMap对象</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> ResultMap <span class="title">resultMapElement</span><span class="params">(XNode resultMapNode,List&lt;ResultMapping&gt; additionalResultMappings)</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">    ErrorContext.instance().activity(<span class="string">"processing "</span>+resultMapNode.getValueBasedIdentifier());</span><br><span class="line">    <span class="comment">//获取Id，默认拼装所有父节点的id或value或property。是一个身份标识，具有唯一性。</span></span><br><span class="line">    String id = resultMapNode.getStringAttribute(<span class="string">"id"</span>,resultMapNode.getValueBasedIdentifier());</span><br><span class="line">    <span class="comment">//获取type属性，表示结果集将被映射为type指定类型的对象</span></span><br><span class="line">    String type = resultMapNode.getStringAttribute(<span class="string">"type"</span>,</span><br><span class="line">                                               resultMapNode.getStringAttribute(<span class="string">"ofType"</span>,</span><br><span class="line">                                           resultMapNode.getStringAttribute(<span class="string">"resultType"</span>,</span><br><span class="line">                                         resultMapNode.getStringAttribute(<span class="string">"javaType"</span>))));</span><br><span class="line">    <span class="comment">//获取extends属性，表示结果集的继承</span></span><br><span class="line">    String extend = resultMapNode.getStringAttribute(<span class="string">"extends"</span>);</span><br><span class="line">    <span class="comment">//自动映射属性。列名自动映射为属性</span></span><br><span class="line">    Boolean autoMapping = resultMapNode.getBooleanAttribute(<span class="string">"autoMapping"</span>);</span><br><span class="line">    <span class="comment">//解析type，获取其类型</span></span><br><span class="line">    Class&lt;?&gt; typeClass = resolveClass(type);</span><br><span class="line">    Discriminator discriminator = <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">//记录解析结果</span></span><br><span class="line">    List&lt;ResultMapping&gt; resultMappings = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">    resultMappings.addAll(additionalResultMappings);</span><br><span class="line">    <span class="comment">//处理子节点</span></span><br><span class="line">    List&lt;XNode&gt; resultChildren = resultMapNode.getChildren();</span><br><span class="line">    <span class="keyword">for</span>(XNode resultChild : resultChildren)&#123;</span><br><span class="line">        <span class="comment">//处理constructor节点</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="string">"constructor"</span>.equals(resultChild.getName()))&#123;</span><br><span class="line">            <span class="comment">//解析构造函数元素，其下的每一个子节点产生一个ResultMapping对象</span></span><br><span class="line">            processConstructorElement(resultChild,typeClass,resultMappings);</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span>(<span class="string">"discriminator"</span>.equals(resultChild.getName())) &#123;<span class="comment">//处理discriminator节点</span></span><br><span class="line">            discriminator = processDiscriminatorElement(resultChild,typeClass,resultMappings);</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;<span class="comment">//处理其余节点</span></span><br><span class="line">            List&lt;ResultFlag&gt; flags = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">            <span class="keyword">if</span>(<span class="string">"id"</span>.equals(resultChild.getName()))&#123;</span><br><span class="line">                flags.add(ResultFlag.ID);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//创建resultMap对象，并添加到resultMappings中</span></span><br><span class="line">            resultMapping.add(buildResultMappingFromContext(resultChild,typeClass,flags));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 创建 ResultMapResolver 对象， 该对象可以生成 ResultMap 对象</span></span><br><span class="line">    ResultMapResolver resultMapResolver = <span class="keyword">new</span> ResultMapResolver(builderAssistant,id,typeClass,extend, discriminator, resultMappings, autoMapping);</span><br><span class="line">    <span class="keyword">try</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> resultMapResolver.resolve();</span><br><span class="line">    &#125;<span class="keyword">catch</span> (IncompleteElementException e)&#123;</span><br><span class="line">        <span class="comment">//若无法创建ResultMap对象，则将该结果添加到incompleteResultMaps集合中</span></span><br><span class="line">        configuration.addIncompleteResultMap(resultMapResolver);</span><br><span class="line">        <span class="keyword">throw</span> e;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="详细解析"><a href="#详细解析" class="headerlink" title="详细解析"></a>详细解析</h3><ul>
<li><p>获取id</p>
<p>id 对于 resultMap 来说是很重要的， 它是一个身份标识。具有唯一性</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取 ID , 默认值会拼装所有父节点的 id 或 value 或 property。</span></span><br><span class="line">    String id = resultMapNode.getStringAttribute(<span class="string">"id"</span>, resultMapNode.getValueBasedIdentifier());</span><br></pre></td></tr></table></figure>

<p>这里涉及到 <code>XNode</code> 对象中的两个函数：getStringAttribute()以及getValueBasedIdentifier()</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getStringAttribute</span><span class="params">(String name, String def)</span> </span>&#123;</span><br><span class="line">    String value = attributes.getProperty(name);</span><br><span class="line">    <span class="keyword">if</span> (value == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> def;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> value;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>该函数是获取 <code>XNode</code> 对象对应 <code>XML</code> 节点的 <code>name</code> 属性值， 如果该属性不存在， 则返回传入的默认值 def。</p>
<p>而在获取 id 的过程中, 默认值是下面这个函数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 生成元素节点的基础 id</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getValueBasedIdentifier</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  StringBuilder builder = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">  XNode current = <span class="keyword">this</span>;</span><br><span class="line">  <span class="comment">// 当前的节点不为空</span></span><br><span class="line">  <span class="keyword">while</span> (current != <span class="keyword">null</span>) &#123;</span><br><span class="line">    <span class="comment">// 如果节点不等于 this， 则在0之前插入 _ 符号， 因为是不断的获取父节点的， 因此是插在前面</span></span><br><span class="line">    <span class="keyword">if</span> (current != <span class="keyword">this</span>) &#123;</span><br><span class="line">      builder.insert(<span class="number">0</span>, <span class="string">"_"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 获取 id， id不存在则获取value, value不存在则获取 property。</span></span><br><span class="line">    String value = current.getStringAttribute(<span class="string">"id"</span>,</span><br><span class="line">        current.getStringAttribute(<span class="string">"value"</span>,</span><br><span class="line">            current.getStringAttribute(<span class="string">"property"</span>, <span class="keyword">null</span>)));</span><br><span class="line">    <span class="comment">// value 非空， 则将.替换为_， 并将value的值加上 []</span></span><br><span class="line">    <span class="keyword">if</span> (value != <span class="keyword">null</span>) &#123;</span><br><span class="line">      value = value.replace(<span class="string">'.'</span>, <span class="string">'_'</span>);</span><br><span class="line">      builder.insert(<span class="number">0</span>, <span class="string">"]"</span>);</span><br><span class="line">      builder.insert(<span class="number">0</span>,</span><br><span class="line">          value);</span><br><span class="line">      builder.insert(<span class="number">0</span>, <span class="string">"["</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 不管 value 是否存在， 前面都添加上节点的名称</span></span><br><span class="line">    builder.insert(<span class="number">0</span>, current.getName());</span><br><span class="line">    <span class="comment">// 获取父节点</span></span><br><span class="line">    current = current.getParent();</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> builder.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>该函数是生成元素节点的id, 如果是这样子的 XML。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">employee</span> <span class="attr">id</span>=<span class="string">"$&#123;id_var&#125;"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">blah</span> <span class="attr">something</span>=<span class="string">"that"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">first_name</span>&gt;</span>Jim<span class="tag">&lt;/<span class="name">first_name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">last_name</span>&gt;</span>Smith<span class="tag">&lt;/<span class="name">last_name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">birth_date</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">year</span>&gt;</span>1970<span class="tag">&lt;/<span class="name">year</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">month</span>&gt;</span>6<span class="tag">&lt;/<span class="name">month</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">day</span>&gt;</span>15<span class="tag">&lt;/<span class="name">day</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">birth_date</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">height</span> <span class="attr">units</span>=<span class="string">"ft"</span>&gt;</span>5.8<span class="tag">&lt;/<span class="name">height</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">weight</span> <span class="attr">units</span>=<span class="string">"lbs"</span>&gt;</span>200<span class="tag">&lt;/<span class="name">weight</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">active</span>&gt;</span>true<span class="tag">&lt;/<span class="name">active</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">employee</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>我们调用</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">XNode node = parser.evalNode(<span class="string">"/employee/height"</span>); node.getValueBasedIdentifier();</span><br></pre></td></tr></table></figure>

<p>则， 返回值应该是</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">employee[$&#123;id_var&#125;]_height</span><br></pre></td></tr></table></figure>
</li>
<li><p>解析结果集中的类型</p>
<p> 结果集的类型， 对应的是一个 <code>JavaBean</code> 对象。通过反射来获得该类型。 </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取type， type 不存在则获取 ofType, ofType </span></span><br><span class="line"><span class="comment">// 不存在则获取 resultType, resultType 不存在则获取 javaType</span></span><br><span class="line">String type = resultMapNode.getStringAttribute(<span class="string">"type"</span>,</span><br><span class="line">    resultMapNode.getStringAttribute(<span class="string">"ofType"</span>,</span><br><span class="line">        resultMapNode.getStringAttribute(<span class="string">"resultType"</span>,</span><br><span class="line">            resultMapNode.getStringAttribute(<span class="string">"javaType"</span>))));</span><br><span class="line"><span class="comment">// ... ...</span></span><br><span class="line"><span class="comment">// 获取 type 对应的 Class 对象</span></span><br><span class="line">Class&lt;?&gt; typeClass = resolveClass(type);</span><br></pre></td></tr></table></figure>

<p> 看源码， 有很多个 def 值， 也就是说， 我们在配置结果集的类型的时候都是有优先级的。但是， 这里有一个奇怪的地方， 我源代码版本（3.5.0-SNAPSHOT）的 的属性， 只有 type, 没有 ofType/resultType/javaType。以下为相应的 DTD 约束： </p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;!ELEMENT resultMap (constructor?,id*,result*,association*,collection*, discriminator?)&gt;</span><br><span class="line">&lt;!ATTLIST resultMap</span><br><span class="line">id CDATA #REQUIRED</span><br><span class="line">type CDATA #REQUIRED</span><br><span class="line">extends CDATA #IMPLIED</span><br><span class="line">autoMapping (true|false) #IMPLIED&gt;</span><br></pre></td></tr></table></figure>

<p>这里可能是考虑到对以前版本的兼容性。</p>
</li>
<li><p>获取继承结果集和自动映射</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">String extend = resultMapNode.getStringAttribute(<span class="string">"extends"</span>);</span><br><span class="line">   Boolean autoMapping = resultMapNode.getBooleanAttribute(<span class="string">"autoMapping"</span>);</span><br></pre></td></tr></table></figure>

<p>这两个属性在配置XML的时候，显得有些可有可无。</p>
</li>
<li><p>解析</p>
<p>根据类型进行解析，获得resultMappings</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个 resultMappings 的链表</span></span><br><span class="line">   List&lt;ResultMapping&gt; resultMappings = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">   <span class="comment">// 将从其他地方传入的additionalResultMappings添加到该链表中</span></span><br><span class="line">   resultMappings.addAll(additionalResultMappings);</span><br><span class="line">   <span class="comment">// 获取子节点</span></span><br><span class="line">   List&lt;XNode&gt; resultChildren = resultMapNode.getChildren();</span><br><span class="line">   <span class="comment">// 遍历解析子节点</span></span><br><span class="line">   <span class="keyword">for</span> (XNode resultChild : resultChildren) &#123;</span><br><span class="line">     <span class="keyword">if</span> (<span class="string">"constructor"</span>.equals(resultChild.getName())) &#123;</span><br><span class="line">       <span class="comment">// 解析构造函数元素，其下的没每一个子节点都会生产一个 ResultMapping 对象</span></span><br><span class="line">       processConstructorElement(resultChild, typeClass, resultMappings);</span><br><span class="line">     &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="string">"discriminator"</span>.equals(resultChild.getName())) &#123;</span><br><span class="line">       <span class="comment">// 解析 discriminator 节点</span></span><br><span class="line">       discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);</span><br><span class="line">     &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">       <span class="comment">// 解析其余的节点</span></span><br><span class="line">       List&lt;ResultFlag&gt; flags = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">       <span class="keyword">if</span> (<span class="string">"id"</span>.equals(resultChild.getName())) &#123;</span><br><span class="line">         flags.add(ResultFlag.ID);</span><br><span class="line">       &#125;</span><br><span class="line">       resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));</span><br><span class="line">     &#125;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<p>除了discriminator节点，其他节点最后都会回到buildResultMappingFromContext方法，该方法为创建ResultMapping对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">   * 获取一行， 如result等， 取得他们所有的属性， 通过这些属性建立 `ResultMapping` 对象</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> context 对于节点本身</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> resultType resultMap 的结果类型</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> flags flag 属性， 对应 ResultFlag 枚举中的属性。 一般情况下为空</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@return</span> 返回 ResultMapping</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="function"><span class="keyword">private</span> ResultMapping <span class="title">buildResultMappingFromContext</span><span class="params">(XNode context, Class&lt;?&gt; resultType, List&lt;ResultFlag&gt; flags)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">    String property;</span><br><span class="line">    <span class="comment">// 获取节点的属性， 如果节点是构造函数（只有name属性， 没有property），</span></span><br><span class="line">    <span class="comment">// 则获取的是 name, 否则获取 property</span></span><br><span class="line">    <span class="keyword">if</span> (flags.contains(ResultFlag.CONSTRUCTOR)) &#123;</span><br><span class="line">      property = context.getStringAttribute(<span class="string">"name"</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      property = context.getStringAttribute(<span class="string">"property"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    String column = context.getStringAttribute(<span class="string">"column"</span>);</span><br><span class="line">    String javaType = context.getStringAttribute(<span class="string">"javaType"</span>);</span><br><span class="line">    String jdbcType = context.getStringAttribute(<span class="string">"jdbcType"</span>);</span><br><span class="line">    String nestedSelect = context.getStringAttribute(<span class="string">"select"</span>);</span><br><span class="line">    <span class="comment">// 获取嵌套的结果集</span></span><br><span class="line">    String nestedResultMap = context.getStringAttribute(<span class="string">"resultMap"</span>,</span><br><span class="line">        processNestedResultMappings(context, Collections.&lt;ResultMapping&gt; emptyList()));</span><br><span class="line">    String notNullColumn = context.getStringAttribute(<span class="string">"notNullColumn"</span>);</span><br><span class="line">    String columnPrefix = context.getStringAttribute(<span class="string">"columnPrefix"</span>);</span><br><span class="line">    String typeHandler = context.getStringAttribute(<span class="string">"typeHandler"</span>);</span><br><span class="line">    String resultSet = context.getStringAttribute(<span class="string">"resultSet"</span>);</span><br><span class="line">    String foreignColumn = context.getStringAttribute(<span class="string">"foreignColumn"</span>);</span><br><span class="line">    <span class="keyword">boolean</span> lazy = <span class="string">"lazy"</span>.equals(context.getStringAttribute(<span class="string">"fetchType"</span>, configuration.isLazyLoadingEnabled() ? <span class="string">"lazy"</span> : <span class="string">"eager"</span>));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 以上获取各个属性节点</span></span><br><span class="line">    <span class="comment">// 解析 javaType， typeHandler， jdbcType</span></span><br><span class="line">    Class&lt;?&gt; javaTypeClass = resolveClass(javaType);</span><br><span class="line">    <span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line">    Class&lt;? extends TypeHandler&lt;?&gt;&gt; typeHandlerClass = (Class&lt;? extends TypeHandler&lt;?&gt;&gt;) resolveClass(typeHandler);</span><br><span class="line">    JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);</span><br><span class="line">    <span class="comment">// 创建resultMapping对象</span></span><br><span class="line">    <span class="keyword">return</span> builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<p>对于discriminator，则处理该元素，并创建鉴别器。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">   * 处理鉴别器</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> context 节点</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> resultType 结果类型</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> resultMappings 列结果集合</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@return</span> 鉴别器</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="function"><span class="keyword">private</span> Discriminator <span class="title">processDiscriminatorElement</span><span class="params">(XNode context, Class&lt;?&gt; resultType, List&lt;ResultMapping&gt; resultMappings)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">    String column = context.getStringAttribute(<span class="string">"column"</span>);</span><br><span class="line">    String javaType = context.getStringAttribute(<span class="string">"javaType"</span>);</span><br><span class="line">    String jdbcType = context.getStringAttribute(<span class="string">"jdbcType"</span>);</span><br><span class="line">    String typeHandler = context.getStringAttribute(<span class="string">"typeHandler"</span>);</span><br><span class="line">    <span class="comment">// 先获取各个属性</span></span><br><span class="line">    <span class="comment">// 取得 javaType 对应的类型</span></span><br><span class="line">    Class&lt;?&gt; javaTypeClass = resolveClass(javaType);</span><br><span class="line">    <span class="comment">// 取得 typeHandler 对应的类型</span></span><br><span class="line">    <span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line">    Class&lt;? extends TypeHandler&lt;?&gt;&gt; typeHandlerClass = (Class&lt;? extends TypeHandler&lt;?&gt;&gt;) resolveClass(typeHandler);</span><br><span class="line">    <span class="comment">// 取得 jdbcType 对应的类型</span></span><br><span class="line">    JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);</span><br><span class="line">    <span class="comment">// 创建 discriminatorMap， 并遍历子节点， 以 value-&gt;resultMap 的方式放入discriminatorMap中</span></span><br><span class="line">    Map&lt;String, String&gt; discriminatorMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">    <span class="keyword">for</span> (XNode caseChild : context.getChildren()) &#123;</span><br><span class="line">      String value = caseChild.getStringAttribute(<span class="string">"value"</span>);</span><br><span class="line">      String resultMap = caseChild.getStringAttribute(<span class="string">"resultMap"</span>, processNestedResultMappings(caseChild, resultMappings));</span><br><span class="line">      discriminatorMap.put(value, resultMap);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 创建鉴别器</span></span><br><span class="line">    <span class="keyword">return</span> builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<p>在鉴别器内部中，也是含有ResultMapping的：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Discriminator</span> </span>&#123;</span><br><span class="line">  <span class="keyword">private</span> ResultMapping resultMapping;</span><br><span class="line">  <span class="keyword">private</span> Map&lt;String, String&gt; discriminatorMap;</span><br><span class="line">  ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



</li>
</ul>
<ul>
<li><p>创建ResultMap对象</p>
<p>解析各个属性和子节点完毕之后，创建ResultMapResolver对象，通过对象可以生成ResultMap。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">   * 创建并添加 ResultMap 到 Configuration 对象中</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> id id, 配置了 id 可以提高效率</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> type 类型</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> extend 继承</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> discriminator 鉴别器</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> resultMappings 列集</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> autoMapping 是否自动映射</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@return</span> 返回创建的 ResultMap 对象</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> ResultMap <span class="title">addResultMap</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">      String id,</span></span></span><br><span class="line"><span class="function"><span class="params">      Class&lt;?&gt; type,</span></span></span><br><span class="line"><span class="function"><span class="params">      String extend,</span></span></span><br><span class="line"><span class="function"><span class="params">      Discriminator discriminator,</span></span></span><br><span class="line"><span class="function"><span class="params">      List&lt;ResultMapping&gt; resultMappings,</span></span></span><br><span class="line"><span class="function"><span class="params">      Boolean autoMapping)</span> </span>&#123;</span><br><span class="line">    id = applyCurrentNamespace(id, <span class="keyword">false</span>);</span><br><span class="line">    extend = applyCurrentNamespace(extend, <span class="keyword">true</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (extend != <span class="keyword">null</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (!configuration.hasResultMap(extend)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IncompleteElementException(<span class="string">"Could not find a parent resultmap with id '"</span> + extend + <span class="string">"'"</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">// 从 configuration 中获取继承的结果集</span></span><br><span class="line">      ResultMap resultMap = configuration.getResultMap(extend);</span><br><span class="line">      <span class="comment">// 获取所集成结果集的所有 ResultMapping 集合</span></span><br><span class="line">      List&lt;ResultMapping&gt; extendedResultMappings = <span class="keyword">new</span> ArrayList&lt;&gt;(resultMap.getResultMappings());</span><br><span class="line">      <span class="comment">// 移除需要覆盖的 ResultMapping 集合</span></span><br><span class="line">      extendedResultMappings.removeAll(resultMappings);</span><br><span class="line">      <span class="comment">// 如果该 resultMap 中定义了构造节点， 则移除其父节点的构造器</span></span><br><span class="line">      <span class="keyword">boolean</span> declaresConstructor = <span class="keyword">false</span>;</span><br><span class="line">      <span class="keyword">for</span> (ResultMapping resultMapping : resultMappings) &#123;</span><br><span class="line">        <span class="keyword">if</span> (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) &#123;</span><br><span class="line">          declaresConstructor = <span class="keyword">true</span>;</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (declaresConstructor) &#123;</span><br><span class="line">        Iterator&lt;ResultMapping&gt; extendedResultMappingsIter = extendedResultMappings.iterator();</span><br><span class="line">        <span class="keyword">while</span> (extendedResultMappingsIter.hasNext()) &#123;</span><br><span class="line">          <span class="keyword">if</span> (extendedResultMappingsIter.next().getFlags().contains(ResultFlag.CONSTRUCTOR)) &#123;</span><br><span class="line">            extendedResultMappingsIter.remove();</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">// 添加需要被继承的 ResultMapping 集合</span></span><br><span class="line">      resultMappings.addAll(extendedResultMappings);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 通过建造者模式创建 ResultMap 对象</span></span><br><span class="line">    ResultMap resultMap = <span class="keyword">new</span> ResultMap.Builder(configuration, id, type, resultMappings, autoMapping)</span><br><span class="line">        .discriminator(discriminator)</span><br><span class="line">        .build();</span><br><span class="line">    <span class="comment">// 添加到 Configuration 对象中</span></span><br><span class="line">    configuration.addResultMap(resultMap);</span><br><span class="line">    <span class="keyword">return</span> resultMap;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>



</li>
</ul>
<p><a href="https://mp.weixin.qq.com/s/zL0d4odAeZIqTTeOesXgYA" target="_blank" rel="noopener">https://mp.weixin.qq.com/s/zL0d4odAeZIqTTeOesXgYA</a></p>
<h2 id="Github示例代码"><a href="#Github示例代码" class="headerlink" title="Github示例代码"></a>Github示例代码</h2><p> <a href="https://github.com/homejim/mybatis-cn" target="_blank" rel="noopener">https://github.com/homejim/mybatis-cn</a> </p>

      
      <!-- reward -->
      
    </div>
      <!-- copyright -->
      
    <footer class="article-footer">
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Mybatis/" rel="tag">Mybatis</a></li></ul>


    </footer>

  </div>

  

  
  
  

  

</article>
    
  </article>
  

  
  <nav class="page-nav">
    
    <a class="extend prev" rel="prev" href="/page/2/">上一页</a><a class="page-number" href="/">1</a><a class="page-number" href="/page/2/">2</a><span class="page-number current">3</span><a class="page-number" href="/page/4/">4</a><a class="page-number" href="/page/5/">5</a><a class="page-number" href="/page/6/">6</a><a class="extend next" rel="next" href="/page/4/">下一页</a>
  </nav>
  
</section>
</div>

      <footer class="footer">
  <div class="outer">
    <ul class="list-inline">
      <li>
        &copy;
        2019-2020
        LinPaiBin
      </li>
      <li>
        
          Powered by
        
        
        <a href="https://hexo.io" target="_blank">Hexo</a> Theme <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul class="list-inline">
      <li>
        
        
        <span>
  <i>PV:<span id="busuanzi_value_page_pv"></span></i>
  <i>UV:<span id="busuanzi_value_site_uv"></span></i>
</span>
        
      </li>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>
    <div class="to_top">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>
      </div>
    </main>
      <aside class="sidebar">
        <button class="navbar-toggle"></button>
<nav class="navbar" style="opacity: 0.5;">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="滨书"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/%E7%94%9F%E6%B4%BB/">生活</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/2019/12/02/AboutMe">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="Search">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
      </aside>
      <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="/images/alipay.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="/images/wechat.jpg">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
      
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/jquery.justifiedGallery.min.js"></script>


<script src="/js/lazyload.min.js"></script>


<script src="/js/busuanzi-2.3.pure.min.js"></script>


<script src="/js/share.js"></script>



<script src="/fancybox/jquery.fancybox.min.js"></script>




<script>
  try {
    var typed = new Typed("#subtitle", {
    strings: ['人生如棋，吾愿为卒','愿你一生努力，一生无憾','不求事事顺意，但求无愧于心'],
    startDelay: 0,
    typeSpeed: 250,
    loop: true,
    backSpeed: 100,
    showCursor: true
    });
  } catch (err) {
  }
  
</script>




<script>
  var ayerConfig = {
    mathjax: false
  }
</script>


<script src="/js/ayer.js"></script>


<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">


<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script>




<script type="text/javascript" src="https://js.users.51.la/20544303.js"></script>
  </div>
</body>

</html>